• 内存泄漏排查


    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提供相应的释放接口,否则内存也是无法被释放的

  • 相关阅读:
    【精品软件】小蔡电脑助手 V2.0
    C++ 数据结构与算法(二)线性表之单链表
    C++ 数据结构与算法:冒泡排序及改进算法
    C++ 数据结构与算法(四)线性表之循环链表
    const int *p、int*const p、和 int const *p 详解
    C++ 指针和引用的区别
    C++ 数据结构与算法(三)线性表之双向链表
    C++ 数据结构与算法(一)线性表之顺序表
    C++数据结构与算法:选择排序
    VC++ 获取文件夹大小
  • 原文地址:https://www.cnblogs.com/shiqi17/p/16248513.html
Copyright © 2020-2023  润新知