中文
注册
我要评分
文档获取效率
文档正确性
内容完整性
文档易理解
在线提单
论坛求助
鲲鹏小智

C/C++内存占用超预期

定位思路

内存泄漏(Memory Leak)是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。应用态+ 内核态 内存占用持续增加,确认内存不足,非虚拟内存原因,如何确认内存泄露问题。定位思路如图 C/C++内存占用超预期定位思路所示。

图1 C/C++内存占用超预期定位思路
  1. 通过cat命令,查看系统还有多少内存,若总体的内存剩余持续减小而不能恢复,此时可怀疑是否发生内存泄露。
    1
    cat /proc/meminfo
    
    MemTotal:       131084400 kB
    MemFree:        18039732 kB
    MemAvailable:   128007632 kB
    Buffers:            3132 kB
    Cached:         107111252 kB
    SwapCached:            0 kB
    Active:          3757036 kB
    Inactive:       103812244 kB
    Active(anon):     455888 kB
    Inactive(anon):    21032 kB
    Active(file):    3301148 kB
    Inactive(file): 103791212 kB
    Unevictable:           0 kB
    Mlocked:               0 kB
    SwapTotal:             0 kB
    SwapFree:              0 kB
    Dirty:                 0 kB
    Writeback:             0 kB
    AnonPages:        404036 kB
    Mapped:           203740 kB
    Shmem:             22024 kB
    Slab:            4728332 kB
    SReclaimable:    3858356 kB
    SUnreclaim:       869976 kB
    KernelStack:       17920 kB
    PageTables:         9076 kB
    NFS_Unstable:          0 kB
    Bounce:                0 kB
    WritebackTmp:          0 kB
    CommitLimit:    65542200 kB
    Committed_AS:    3760688 kB
    VmallocTotal:   135290290112 kB
    VmallocUsed:           0 kB
    VmallocChunk:          0 kB
    HardwareCorrupted:     0 kB
    AnonHugePages:    149504 kB
    ShmemHugePages:        0 kB
    ShmemPmdMapped:        0 kB
    HugePages_Total:       0
    HugePages_Free:        0
    HugePages_Rsvd:        0
    HugePages_Surp:        0
    Hugepagesize:       2048 kB

    参数说明

    • MemFree:剩余内存
    • Slab:slab内存占用
    • SReclaimabl:slab中可回收的slab内存占用
    • SUnreclaim:slab中不可回收的slab内存占用
  2. 使用top命令按M,按照内存占用大小进行排序,确认是否进程非虚拟内存的占用超过预期,并确定占用大量内存的进程。
    • 是,获得进程的进程号$pid。

    • 否,进入5

    top命令默认列名含义解释:

    • VIRT(Virtual Memory Usage):虚拟内存,即进程“需要的”虚拟内存大小,包括进程使用的库、代码、数据等。假如进程申请100MB的内存,但实际只使用了10MB,那么它会增长100MB,而不是实际的使用量。
    • RES(Resident Memory Usage):常驻内存,即进程当前使用的内存大小,但不包括swap out。包含其他进程的共享。如果申请100m的内存,实际使用10MB,它只增长10MB,与VIRT相反。关于库占用内存的情况,它只统计加载的库文件所占内存大小。
    • SHR(Shared Memory):共享内存,即除了自身进程的共享内存,也包括其他进程的共享内存。虽然进程只使用了几个共享库的函数,但它包含了整个共享库的大小。计算某个进程所占的物理内存大小公式RES – SHR。swap out后,它将会降下来。
    • DATA:数据占用的内存。如果top没有显示,按f键可以显示出来。真正的该程序要求的数据空间,是真正在运行中要使用的。

    更多top命令参数释义及参考请参见top命令参数参考

  3. 使用cat /proc/$pid/stat命令,确认占用的物理内存超过预期。

    参数释义:

    • size:任务虚拟地址空间大小
    • Resident:正在使用的物理内存大小
    • Shared:共享页数
    • Trs:程序所拥有的可执行虚拟内存大小
    • Lrs:被映像到任务的虚拟内存空间的库的大小
    • Drs:程序数据段和用户态的栈的大小
    • dt:脏页数量(单位为页)
  4. 结合代码逻辑,修改代码,保证申请内存的代码和释放内存成对。
    • 若问题解决,则确认修改,合入原代码。
    • 若问题未解决,增加定位信息,重新编译运行。
  5. 2,未定位到大量进程内存占用,则应该怀疑是内核/或因应用进程的操作导致内核空间的内存泄漏,每隔一段时间可以执行cat /proc/slabinfo或者slabtop命令查看。确定内核资源消耗增长较快的slab cache。

    上图参数释义:

    • SLABS:slab是用来承载数据的实体内存区域。每个slab都是一段连续的内存区域。slab是slab分配器管理的最小单元,由一个或多个page组成。上图显示一共有677900个slab。
    • OBJ/SLAB:每个slab包含的对象数,上图中有39个对象。
    • OBJS:OBJ是slab内部存放的元素,上图中有26438100个对象。
    • OBJ SIZE:每个对象占用的大小,上图中为0.10KB

    所以CACHE SIZE = 26438100 *0.1K = 2711600K

    上图参数释义:

    • name:对象(slab object)的名称。
    • active_objs:活动对象个数,即被申请走的(正在被使用)对象个数。
    • num_objs:总对象个数,slab本身具备缓存作用,所以num_objs可能会比active_objs要大,这是一种合理的现象。
    • objsize:每个对象大小,以字节为单位。
    • objperslab:slab中存放的是对象,这个指标表示一个slab中包含多少个对象。
    • pagesperslab : tunables:一个slab占用几个page内存页。可以算一下,一个slab的大小为320*12=3840,小于4096(以内存页为4K为例),所以一个slab只需占用1个page内存页。另外,cache对象本身需要存储一个额外的管理信息,即有overhead,所以一个xfs_buf slab的大小不止3840。
    • active_slabs:活动slab个数。
    • num_slabs:总slab个数。
  6. 寻找到问题点,修改代码,重新编译进行验证。
    • 若问题解决,则确认修改,合入原代码。
    • 若问题未解决,增加定位信息,重新编译运行。

使用DevKit工具也可以定位内存泄露问题,详见任务创建

案例:资源泄露问题定位

问题现象

某软件在服务器上运行出现问题,在没有压力加载的情况下,内存占用超过80%。

定位过程:

  1. 通过free命令看到剩余内存不足,但无法确定造成内存问题的进程。
  2. 使用top命令并按M让进程按内存排序,发现无占用大量内存的特殊进程。

  3. 通过cat /proc/meminfo命令只需观看,发现slab占用过高,并且通过监控发现,slab占用持续增加。
  4. 通过cat /proc/slabinfo命令,发现dentry在slab中的占用量达到了非常高的程度,dentry是内存中表示目录和文件的对象,高程度的dentry项可能意味着系统有大量被打开的文件。

    与空闲服务器对比,两者的dentry obj数量差距为383322,此项多占用了70G的内存。

    dentry的作用:当读写文件时内核会为该文件对象建立一个dentry,并将其缓存起来,方便下一次读写时直接从内存中取出提高效率。

    通常情况下,dentry过高的有两种解决方法:

    • 方法一:

      使用sudo sh -c "echo 2 > /proc/sys/vm/drop_caches"命令来清除cache。

      缺点是执行命令过程容易暂时停止执行几分钟。

    • 方法二:

      调整内核参数vm.vfs_cache_pressure,例如可以设置vm.vfs_cache_pressure=10000。

      vm.vfs_cache_pressure控制内核回收用于dentry和inode cache内存的倾向。默认值是100,内核会根据pagecache和swapcache的回收情况,让dentry和inode cache的内存占用量保持在一个相对公平的百分比上。减小vfs_cache_pressure会让内核更倾向于保留dentry和inode cache。当vfs_cache_pressure等于0,在内存紧张时内核也不会回收dentry和inode cache,这容易导致OOM。如果vfs_cache_pressure的值超过100,内核会更倾向于回收dentry和inode cache。

  5. 使用lsof -w| wc -l命令查看进程打开数,发现进程中启动了大量的火狐进程,占用了大量的内存资源。

  6. 根据上述信息,确定是客户代码业务逻辑中启动了大量的火狐进程导致了过量的内存占用。通过修改代码,重新编译运行,问题未复现,确认修改代码合入,验证问题解决。
搜索结果
找到“0”个结果

当前产品无相关内容

未找到相关内容,请尝试其他搜索词