• Android 内存分析


    一、检查meminfo

    console:/ # cat /proc/meminfo                                                 

    MemTotal:        1892784 kB

    MemFree:          281508 kB

    MemAvailable:    1089928 kB

    Buffers:           13740 kB

    Cached:           841000 kB

    SwapCached:            0 kB

    Active:           518860 kB

    Inactive:         734844 kB

    Active(anon):     401492 kB

    Inactive(anon):     4824 kB

    Active(file):     117368 kB

    Inactive(file):   730020 kB

    Unevictable:         256 kB

    Mlocked:             256 kB

    SwapTotal:             0 kB

    SwapFree:              0 kB

    Dirty:                52 kB

    Writeback:             0 kB

    AnonPages:        399252 kB

    Mapped:           257672 kB

    Shmem:              7368 kB

    Slab:             108576 kB

    SReclaimable:      40048 kB

    SUnreclaim:        68528 kB

    KernelStack:       23232 kB

    PageTables:        27188 kB

    NFS_Unstable:          0 kB

    Bounce:                0 kB

    WritebackTmp:          0 kB

    CommitLimit:      946392 kB

    Committed_AS:   56310412 kB

    VmallocTotal:   258998208 kB

    VmallocUsed:      108496 kB

    VmallocChunk:   258743780 kB

    Meminfo里面列出来很多项,只需要关注如下几条:

    MemTotal: 总内存大小

    MemFree: 可以直接使用的空闲的内存大小

    MemAvailable: 可以使用的内存,包括MemFree和Cached/Buffers/Slab中可以回收的部分。

    Buffers: 直接读写的块设备和文件系统元数据(如super block)所使用的内存。

    Cached: 从磁盘读取的文件内容的缓存大小,另外也包含了Shmem内存页

    Active(anon):匿名页内存,主要是用户模式下的堆、栈,以及shmem,最近访问过

    Inactive(anon):匿名页内存,主要是用户模式下的堆、栈,以及shmem,最近没有访问过

    Active(file):基于文件的内存页,包含cache和buffer,但是不包含Shmem内存页,最近访问过

    Inactive(file): 基于文件的内存页,包含cache和buffer,但是不包含Shmem内存页,最近没有访问过

    AnonPages:匿名页内存,但是不包括Shmem 。所以AnonPages大约等于Active(anon) + Inactive(anon) - Shmem

    Mapped: 设备和文件等映射的大小,共享内存、可执行程序的文件、动态库、mmap的文件等都统计在这里

    Slab: slab 分配器分配的内存,主要是内核中使用

    SReclaimable:slab中可回收的内存。

    SUnreclaim:slab中不可回收的内存。

    如果机器在运行的过程中MemAvailable持续减小,就可以怀疑系统中存在内存泄漏。但是并不是MemAvailable减小就一定存在内存泄漏,还要进一步分析减少的内存被什么占用了。如果Active(anon)+Inactive(anon)所占用的内存增加,说明用户进程占用的内存增加。如果SUnreclaim所占用的内存增加,说明kernel占用的内存增加。知道了减少的内存是被用户进程还是kernel占用之后,要分析是哪个用户进程或内核哪部分占用了内存。

    二、用户进程占用内存增加

    用户进程的内存页分为两种:基于文件的内存页和匿名内存页。

    1. 进程的可执行文件、动态库、程访问的文件占用的内存,都是基于文件的内存页,这些都会统计进cache和Active(file)/ Inactive(file)中。
    2. 用户进程的堆和栈属于匿名内存页,统计在AnonPages和Active(anon)/Inactive(anon)中。
    3. 还有有一个比较特殊的内存: shmem,它是通过tmpfs文件系统来实现的,所以它占用的内存会被统计在cache中,但是它又没有磁盘介质,所以它占用的内存实际上是属于匿名内存。所以Shmem被统计在Inactive(anon)/ Active(anon)中,而没有被统计在Inactive(file)/ Active(file)中

    Active(file)/ Inactive(file)中的内存是可回收的,当系统内存不足时,系统会将这部分内存释放掉,所以这部分内存不会存在内存泄漏。所以要判断用户进程是否有内存泄漏,我们只需要看Active(anon)/Inactive(anon)是否持续增加就可以了。一旦发现Active(anon)+Inactive(anon)持续增加,我们就可以通过dumpsys meminfo命令来检查进程所占用的内存空间。如果哪个进程有持续的内存泄漏,它占用的内存一定会持续增加,根据这个信息我们就可以找到可疑的进程,再进一步分析。

    dumpsys meminfo

    Applications Memory Usage (in Kilobytes):

    Uptime: 702679 Realtime: 702679

    Total PSS by process:

         86,379K: system (pid 1375)

         84,592K: surfaceflinger (pid 537)

         63,558K: com.android.systemui (pid 1613)

         56,996K: com.histone.postest (pid 3111 / activities)

         29,792K: zygote (pid 576)

         29,053K: com.android.launcher3ex (pid 2247 / activities)

         25,333K: com.android.phone (pid 1944)

         24,179K: com.android.inputmethod.latin (pid 3134)

         22,759K: com.android.bluetooth (pid 1787)

         21,780K: com.google.android.inputmethod.pinyin (pid 1800)

         21,446K: mm-qcamera-daemon (pid 605)

         17,518K: com.android.calculator2 (pid 2998 / activities)

         17,132K: zygote64 (pid 575)

         13,696K: com.android.chrome (pid 2963)

         13,238K: com.android.settings (pid 1823)

         10,341K: android.process.acore (pid 2131)

          9,689K: audioserver (pid 577)

          9,300K: com.android.email (pid 2565)

          8,793K: rild (pid 592)

          8,507K: .dataservices (pid 2173)

          8,494K: netmgrd (pid 663)

          8,031K: rild (pid 650)

          7,223K: ims_rtp_daemon (pid 1116)

          6,918K: cnd (pid 556)

          5,935K: imscmservice (pid 1118)

          5,810K: com.android.calendar (pid 2515)

          5,809K: android.process.media (pid 3041)

          5,758K: mm-pp-dpps (pid 549)

          5,417K: com.android.providers.calendar (pid 2551)

          5,267K: com.histone.pos.shareduserfile (pid 2777)

          5,223K: qseeproxydaemon (pid 603)

    三、内核内存泄漏

    内核中主要通过slab来动态分配内存。Slab分配的内存又分为SReclaimable和SUnreclaim,其中SReclaimable是可回收的,SUnreclaim是不可回收的。我们要检查内核中是否有内存泄漏,只需要检查SUnreclaim有没有持续增加即可。一旦发现SUnreclaim持续增加,我们需要检查slabinfo,

    • 打开如下内核宏

    CONFIG_STACKTRACE=y

    CONFIG_DEBUG_SLAB=y

    CONFIG_SLABINFO=y

     增大buffer

    • 运行cat /proc/slabinfo命令,检查哪个slab持续增加

    如上图,我们在海信SC60的slabinfo中发现kmalloc-8192占用的内存持续增加,所以需要对kmalloc-8192做进一步分析。

    •  运行echo 1 > /sys/kernel/slab/xxx/trace,然后dmesg,其中xxx是对应的slab名称。在dmesg中,我们可以看到相应slab申请和释放的callstack。但是这个方法有个缺点,如果slab申请和释放很频繁,dmesg log会非常多,甚至会引起系统卡死。
    •  运行cat /sys/kernel/slab/xxx/alloc_calls 

     

    如上图,这个命令会把当前申请的slab的函数打印出来,同时还会打印出每个函数申请slab的次数,如上图__netdev_alloc_skb申请了192次kmalloc-8192。这里边只列出来当前申请了,还没有被释放的内存次数。我们可以观察系统在运行中,哪个函数申请slab的次数会持续增加,如果这个函数申请slab持续增加,就需要检查这个函数对应代码是否存在内存泄漏。

  • 相关阅读:
    计算机毕业设计SSMjspm学科竞赛管理系统【附源码数据库】
    asp.net core mvc之路由
    四、W5100S/W5500+RP2040树莓派Pico<TCP Server数据回环测试>
    【Vim】模式的切换、常用命令总结
    从运维到运维大神,只需要一个正确的选择
    读《反无效努力工作法》
    安装VMware和安装虚拟机Linux和网络配置
    C语言变量的定义和赋值
    MyBatis整合多数据源
    【历史上的今天】8 月 9 日:人工智能理论的奠基者诞生;鸿蒙 OS 发布;“云计算”概念被提出
  • 原文地址:https://blog.csdn.net/superjaingchao/article/details/126185063