内存泄漏排查

pmap 命令查看内存分布:https://blog.csdn.net/weixin_39639119/article/details/85704569

 

查现象
这里先入为主,根据提供的信息是用户态占用差不多,所以走了很多弯路,查了很久的内核占用。
由于内核是存在空洞的,因此无法确定具体哪些模块使用了哪些内存。因此重新着手分析全部的内存占

比较/proc/meminfo
对比两台设备的/proc/meminfo信息:10.222.3.18的用户态进程使用了2187M;10.222.3.49用户
态进程1897M进程,相差了300M。所以问题出现在用户态。
(这里需要说明的是 Active + Inactive就是用户态使用内存的综合,感兴趣的可以去了解下内核的内
存管理)
(10.222.3.18)
(10.222.3.49)
比较RSS
虽然说rss并不能够完全准确的代表进程使用的物理内存大小,但是能够看出些端倪,我们能够比
较相同进程的占用来确定是否有进程占用差异很大。
通过ps获取rss跟进程的对应关系,比较占用较大的一些进程;可以发现fwlog和logsd相加起来
10.222.3.18要比10.222.3.49多出约250M。
这里锁定了fwlog来查看。

fwlog对比
依然是对比,这次我们对比两个进程的内存空间,通过pmap -x pid的方式来对比,结果如下。
可以看到10.222.3.18比10.222.3.49多使用了约140M的匿名内存页,而且这些匿名内存页都是Dirty的
状态,也就是说这些内存页是正在被使用的,根据fwlog的功能分析,它不应该长时间持有这么大的内
存,说明出现了内存泄漏。

 

 

 

分析泄漏内存的内容
我们可以用gdb来dump出想要的进程内存,例如0x7f21b8000000 这一块,通过如下方式:
gdb: dump memory /fwlog/test_memory.dump 0x7f21b8000000 0x7F21BBFFF000
(这里可以通过gdb -p进入后来执行命令,也可以通过编写test_dump.gdb,然后gdb -q -x
test_dump.gdb -p pid来实现无交互的gdb,这个对于那些无法长时间中断的进程调试很有效。)

vim test_dump.gdb

dump memory /fwlog/test_memory.dump 0x7f21b8000000 0x7F21BBFFF000

通过hexdump来查看dump出来的内存:可以看到里面存的是session相关的字符串,而且是json
格式的字符串。fwlog中只有一个地方用到了session的json转字符串

 

分析fwlog代码
在fwlog/fwlog/write_to_thrid.cc中的write_to_third函数中。初次分析好像没有什么问题,
json_object_put会释放掉json_str;深入看了以后还是证明这个json库是没有问题的,虽然写的很复
杂。
在查看json库无果了以后,开始怀疑kafka发送那里可能拷贝一份json_str,因为它调用的是asyn
接口,一般来说是异步的,也就是说在kafka处理前,这个json_str已经走完了释放逻辑。

在kafka的实现中可以看到,它进行了produce以后就退出了,而且参数明确表示它拷贝了
payload。

当kafka 服务端异常时,客户端可能出现msg的积累,积累数量可以在代码中找到,限制是10W条和1G,按照msg 大学自傲来算,最多累积约200M

除了fwlog进程,还有logsd和auditd都使用了kafka,这三个进程合起来比另外一台主机上多使用
了300M内存。所以所谓的内存泄漏的原因是由于kafka服务端连不上导致,但是我们在编码过程中应该
识别到这种风险,毕竟内存的增长可能导致OOM,在10.222.3.18上就出现了OOM杀进程的问题。
最后讨论的结果是通过配置限制kafka缓存的消息数和消息大小,来避免出现占用过多内存的问
题。

 

 

在python开发中有我们可能会用到一些C库的so里面的功能,有些会使用ctype来进行操作,在使用的时候需要注意内存释放问题:
1、ctype pointer的释放问题
xxx
result = ctypes.pointer(xxx)
xxx
上面的代码中result转换成为了ctype的指针,可以传递给so里面的c函数作为参数,但是需要注意,不论是否进行其它操作,一旦调用了ctypes.pointer,这个result是会被缓存起来的,
它并不会被主动释放,即使result的生命周期结束。这里必须在使用完后配合调用ctypes._reset_cache()来释放空间

2、so里面有内存申请
so里面如果有malloc和mmap一类的内存申请,那么需要so提供相应的释放接口,否则内存也是无法被释放的

posted @ 2022-05-30 10:04  G1733  阅读(535)  评论(0编辑  收藏  举报