Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5226930
  • 博文数量: 1696
  • 博客积分: 10870
  • 博客等级: 上将
  • 技术积分: 18357
  • 用 户 组: 普通用户
  • 注册时间: 2007-03-30 15:16
文章分类
文章存档

2017年(1)

2016年(1)

2015年(1)

2013年(1)

2012年(43)

2011年(17)

2010年(828)

2009年(568)

2008年(185)

2007年(51)

分类: LINUX

2010-03-20 00:23:32

一次内存泄漏问题定位过程与分析


现场:

逻辑server服务器处理能力骤降, 客户端请求大量失败.  逻辑server的统计数据显示,请求量略有增长(客户端重试的结果), log内容显示访问外部接口有一定失败.

分析:

第一反应是外部接口失败导致进程处理堵塞,大量请求被堵塞后丢弃导致客户端重试. vmstat 1看了一下, 发现b字段保持在20-40之间,wa字段值远大于0, 说明进程在等待输入输出而被阻塞. 而swap的si字段值很大,说明系统大量使用交换分区,难道有内存泄漏? 

procs -----------memory---------- ---swap-- -----io---- -system-- -----cpu------
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
27 21 1052252 5415680   7308  29892    1    1     1     1    0    0  8  8 82  2  0
30 22 1052252 5414936   7308  30276  644    0   644     8 15045 27172  4  3 52 40  0
19 22 1052252 5414440   7328  29640  616    0   620   176 15259 26953  4  3 42 50  0
 3 21 1052252 5413696   7340  30084  572    0   572    32 15385 26809  3  3 45 48  0
 0 21 1052252 5413216   7340  29412  672    0   672     0 15105 26989  4  3 30 63  0

top 看了一下, 发现单个处理进程的RES占到了300m,而SHR占用了34m,SHR是进程启动时分配的共享内存,数值是合理的,而RES字段经验值是在36m- 40m左右,说明有内存泄,因此重启了一下进程进行确认,重启之后top如下所示:

top - 13:38:13 up 31 days, 22:15,  1 user,  load average: 0.95, 1.57, 1.97
Tasks: 112 total,   8 running, 104 sleeping,   0 stopped,   0 zombie
Cpu(s): 17.9%us,  1.8%sy,  0.0%ni, 79.5%id,  0.0%wa,  0.0%hi,  0.9%si,  0.0%st
Mem:  16429836k total,  2236360k used, 14193476k free,   443520k buffers
Swap:  2104504k total,        0k used,  2104504k free,  1201280k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                               
 8901 root      15   0 74816  38m  34m S    7  0.2   2:38.97  logic_worker                                                      
 9003 root      15   0 74840  38m  34m S    7  0.2   2:39.12  logic_worker

重启后,发现RES字段在不断增长,并且在SHR稳定在34m后还在持续上升,可以确定有内存泄漏。

解决:

查看进段时间的内存日报,发现曲线自2.3号发布新版本后内存使用量持续上升,从正常状态的3.3G,用到了8.7G,到今天内存已全部用尽,使用 了交换分区,才出现异常。

对比当日版本代码变更,很快发现在一个外部库使用中,出现了内存泄漏,代码大致如下。

char *ptr;

int ret = Encode(ptr, len);

if (ret <0 )

{

    return ErrorEncode;

}

ret = send(ptr, len);

if (ret <0 )

{

    return ErrorSend;

}

return 0;

重新查看接口描述,发现ptr是在Encode里被malloc的,需要外部释放,于是修改代码如下:

char *ptr=NULL;

do

{

    int ret = Encode(ptr, len);

    if (ret <0 )

    {

        break;

    }

    ret = send(ptr, len);

    if (ret <0 )

    {

        break;

    }

}

if (NULL == ptr)

{

    free(ptr);

}

return ret;

修改后发布,10分钟后top观察,发现RES字段稳定在36m,问题解决。

总结:

1. 在使用外部库和接口时,一定要弄清楚api的使用方法和注意事宜,另外,在编写接口时也注意,最好不要在内部申请内存,而依赖外部释放,可以把上面 Encode和Send封装到一个类中,或者一个接口中,接口本身负责编码和发送,内存申请和释放,调用者只需要知道返回码即可。

2. 在出现类似运营问题时,注意看系统参数是否异常,如果vmstat看 wa 和 si 值都异常,再综合top便可以看出,进程异常并不是因为请求量突增,处理时延而导致切换,而是因为内存泄漏的原因。

3. 注意对比监控曲线,如网络包量,请求量,内存使用,io使用等,通过对比,便可以看出,异常出现的时间点,结合代码变更便可定位出原因所在。


阅读(808) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~