內(nèi)存使用情況與監(jiān)測

//kernel-4.9/mm/page_alloc.c 
static void show_migration_types(unsigned char type)
{ 
        static const char types[MIGRATE_TYPES] = {
                [MIGRATE_UNMOVABLE] = 'U', 
                [MIGRATE_MOVABLE] = 'M', 
                [MIGRATE_RECLAIMABLE] = 'E', 
                [MIGRATE_HIGHATOMIC] = 'H', 
#ifdef CONFIG_CMA 
                [MIGRATE_CMA] = 'C', 
#endif 
#ifdef CONFIG_MEMORY_ISOLATION 
                [MIGRATE_ISOLATE] = 'I', 
#endif }; 
...... }

(0). Android/Linux 內(nèi)存分配的兩個重要策略.

Linux 在分配內(nèi)存時, 為了節(jié)省內(nèi)存, 按需分配, 使用了延時分配以及Copy-On-Write 的策略.

延時分配即針對用戶空間申請memory 時, 先只是明面上的分配虛擬空間, 等到真正操作memory 時, 才真正分配具體的物理內(nèi)存, 這個需要借助MMU 的data abort 轉(zhuǎn)換成page fault來達(dá)成. 這樣就可以極大的避免因user space過度申請memory, 或者錯誤申請memory造成的memory浪費.

而Copy-On-Write 即是在進(jìn)程fork 時, 子進(jìn)程和父進(jìn)程使用同一份memory, 只有當(dāng)某塊memory 被更新時, 才重新copy 出新的一份. 這個在android 上表現(xiàn)也非常顯著, 上層app 包括system server 都由zygote fork 出來, 并且沒重新exec 新的bin, ART VM/Lib 的memory 都是共享的, 可以極大的節(jié)省Memory 的使用.

對應(yīng)的我們在評估一個進(jìn)程的memory 使用時, 我們往往就需要觀察它使用的虛擬的memory 空間, 它真實的使用的物理memory, 它和其他進(jìn)程有均攤多少memory, 即:

  • VSS- Virtual Set Size 虛擬耗用內(nèi)存(包含共享庫占用的內(nèi)存)
  • RSS- Resident Set Size 實際使用物理內(nèi)存(包含共享庫占用的內(nèi)存)
  • PSS- Proportional Set Size 實際使用的物理內(nèi)存(比例分配共享庫占用的內(nèi)存)
  • USS- Unique Set Size 進(jìn)程獨自占用的物理內(nèi)存(不包含共享庫占用的內(nèi)存)

(1). 內(nèi)存的整體使用情況.

要分析memory leaks, 你需要知道總體的內(nèi)存使用情況和劃分. 以判斷內(nèi)存泄露是發(fā)生在user space, kernel space, mulit-media 等使用的memory

  • user space 使用的memory 即通常包括從進(jìn)程直接申請的memory, 比如 malloc: 先mmap/sbrk 整體申請大塊Memory 后再malloc 細(xì)分使用, 比如stack memory, 直接通過mmap 從系統(tǒng)申請; 以及因user space 進(jìn)程打開文件所使用的page cache, 以及使用ZRAM 壓縮 user space memory 存儲所占用的memory.

  • kernel space 使用的memory 通常包括 kernel stack, slab, page table, vmalloc, shmem 等.

  • mulit-media 使用的memory 通常使用的方式包括 ion, gpu 等.

  • 其他方式的memory 使用, 此類一般直接從buddy system 中申請出以page 為單位的memory, android 中比較常見如ashmem.(不懂控硼,但是有內(nèi)存黑洞會直接alloc_page申請內(nèi)存)

而從進(jìn)程的角度來講, 通常情況下進(jìn)程所使用的memory, 都會通過mmap 映射到進(jìn)程空間后訪問使用(注: 也會一些非常特別異常的流程, 沒有mmap 到進(jìn)程空間), 所以進(jìn)程的memory maps 資訊是至關(guān)重要的. 對應(yīng)在AEE DB 里面的file 是 PROCESS_MAPS

下面枚舉一些關(guān)鍵的段:

 b1100000-b1180000 rw-p 00000000 00:00 0                                  [anon:libc_malloc]

malloc 通過jemalloc(Android R和S 后準(zhǔn)備切換到Scudo) 所管控的空間, 常見的malloc leaks 都會可以看到這種libc_malloc段空間顯著增長

 address           perms offset  dev    inode               pathname

aefe5000-af9fc000 r-xp 00000000 103:0a 25039               /data/app/in.startv.hotstar-c_zk-AatlkkDg2B_FSQFuQ==/lib/arm/libAVEAndroid.so

af9fc000-afa3e000 r--p 00a16000 103:0a 25039               /data/app/in.startv.hotstar-c_zk-AatlkkDg2B_FSQFuQ==/lib/arm/libAVEAndroid.so

afa3e000-afad2000 rw-p 00a58000 103:0a 25039               /data/app/in.startv.hotstar-c_zk-AatlkkDg2B_FSQFuQ==/lib/arm/libAVEAndroid.so

第一段 "r-xp" 則是只讀并可執(zhí)行的主體代碼段. 第二段 "r--p" 則是這個lib 使用的只讀變量段 , 第三段 "rw-p" 則是這個lib 使用的數(shù)據(jù)段.

7110f000-71110000 rw-p 00000000 00:00 0                                 [anon:.bss]

71712000-71713000 rw-p 00000000 00:00 0                                 [anon:.bss]

71a49000-71a4a000 rw-p 00000000 00:00 0                                 [anon:.bss]

BSS(Block Started by Symbol) 段, 存放進(jìn)程未初始化的static 以及 gloal 變量, 默認(rèn)初始化時全部為0. 通常此類不會有memory leaks, 基本上長度在程序啟動時就已經(jīng)決定了.

//java thread

6f5b0b2000-6f5b0b3000 ---p 00000000 00:00 0 [anon:thread stack guard]

6f5b0b3000-6f5b0b4000 ---p 00000000 00:00 0

6f5b0b4000-6f5b1b0000 rw-p 00000000 00:00 0

//native thread

74d0d0e000-74d0d0f000 ---p 00000000 00:00 0 [anon:thread stack guard]

74d0d0f000-74d0e0c000 rw-p 00000000 00:00 0

pthread stack 使用memory, 注意目前pthread create 時只標(biāo)注了它底部的 "thread stack guard", 默認(rèn)pthread stack 大小是1M - 16K. guard 是 4K. 注意的是java thread 在art 里面還會再隔離一個page, 判斷收到的SIGSEGV 是否為StackOverflowError.

7e9cf16000-7e9cf17000 ---p 00000000 00:00 0                              [anon:thread signal stack guard]

7e9cf17000-7e9cf1b000 rw-p 00000000 00:00 0                              [anon:thread signal stack]

對應(yīng)Pthread signal stack, 大小為16K,同樣底部有g(shù)uard 保護(hù).

7f31245000-7f31246000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]

7f31246000-7f31249000 rw-p 00000000 00:00 0                              [anon:bionic TLS]

對應(yīng)Pthread 的TLS, 長度為12K, 同樣底部有g(shù)uard 保護(hù).

 edce5000-edce6000 rw-s 00000000 00:05 1510969      /dev/ashmem/shared_memory/443BA81EE7976CA437BCBFF7935200B2 (deleted)

此類是ashmem, 訪問/dev/ashmem 然后申請的memory, 通常比較關(guān)鍵是要確認(rèn)它的name, 一般從它的name 可以明確得知memory 的申請位置. 至于 (deleted) 標(biāo)識, 是指 mmap 時有帶MAP_FILE flag, 并且對應(yīng)的path file已經(jīng)unlink 或者不存在.

7e8d008000-7e8d306000 rw-s 00000000 00:0a 7438                           anon_inode:dmabuf

7e8d306000-7e8d604000 rw-s 00000000 00:0a 7438                           anon_inode:dmabuf

7e8d604000-7e8d902000 rw-s 00000000 00:0a 7438                           anon_inode:dmabuf

7e8d902000-7e8dc00000 rw-s 00000000 00:0a 7438                           anon_inode:dmabuf

ion memory 段. ion buffer 的 vma name 標(biāo)注成dmabuf, 即已經(jīng)mmap 的ion memory 可以從這個直接統(tǒng)計算出.

注意的是, maps 打印的資訊只是地址空間, 即是虛擬地址空間占用情況, 而實際的具體的memory 占用多少需要審查 proc/pid/smaps. 666杖虾,smaps和maps區(qū)別

比如:

7e8ea00000-7e8ee00000 rw-p 00000000 00:00 0                              [anon:libc_malloc]

Name:           [anon:libc_malloc]

Size:               4096 kB

Rss:                 888 kB

Pss:                 888 kB

Shared_Clean:          0 kB

Shared_Dirty:          0 kB

Private_Clean:         0 kB

Private_Dirty:       888 kB

Referenced:          888 kB

Anonymous:           888 kB

AnonHugePages:         0 kB

ShmemPmdMapped:        0 kB

Shared_Hugetlb:        0 kB

Private_Hugetlb:       0 kB

Swap:                  0 kB

SwapPss:               0 kB

KernelPageSize:        4 kB

MMUPageSize:           4 kB

Locked:                0 kB

VmFlags: rd wr mr mw me nr

比如這段jemalloc 使用的memory, 對應(yīng)是一個4M 大小, 但實際目前使用的RSS=PSS=888K, 即還有大部分沒有真實填充memory.

同樣人為的查看maps 比較耗時, 目前在android 里面有 procrank, showmap, pmap 等命令可供查看.

procrank 根據(jù)進(jìn)程使用的memory 進(jìn)行排序統(tǒng)計系統(tǒng)中進(jìn)程的memory 使用量, 不過它一般沒有統(tǒng)計ion 等資訊. 注意的是這個命令默認(rèn)只編譯到了debug 版本.

 k71v1_64_bsp:/ # procrank -h

Usage: procrank [ -W ] [ -v | -r | -p | -u | -s | -h ]

    -v  Sort by VSS.

    -r  Sort by RSS.

    -p  Sort by PSS.

    -u  Sort by USS.

    -s  Sort by swap.

        (Default sort order is PSS.)

    -R  Reverse sort order (default is descending).

    -c  Only show cached (storage backed) pages

    -C  Only show non-cached (ram/swap backed) pages

    -k  Only show pages collapsed by KSM

    -w  Display statistics for working set only.

    -W  Reset working set of all processes.

    -o  Show and sort by oom score against lowmemorykiller thresholds.

    -h  Display this help screen.

showmap 根據(jù)進(jìn)程的maps/smaps 進(jìn)行統(tǒng)計排序, 注意的是這個命令默認(rèn)只編譯到了debug 版本.

 k71v1_64_bsp:/ # showmap

showmap [-t] [-v] [-c] [-q]

        -t = terse (show only items with private pages)

        -v = verbose (don't coalesce maps with the same name)

        -a = addresses (show virtual memory map)

        -q = quiet (don't show error if map could not be read)

pmap 把maps 的每個段打印出來, 如果使用-x 則會使用smaps 中數(shù)據(jù)匹配, 統(tǒng)計PSS, SWAP 等.

OP46E7:/ # pmap --help

usage: pmap [-xq] [pids...]

Reports the memory map of a process or processes.

-x Show the extended format

-q Do not display some header/footer lines

從系統(tǒng)角度來看memory 的使用情況, 通常會習(xí)慣性簡單的查看 proc/meminfo:

下面簡單和大家分享具體的含義.

 k71v1_64_bsp:/ # cat proc/meminfo

MemTotal:        3849612 kB    
MemFree:          206920 kB
MemAvailable:    1836292 kB
Buffers:           73472 kB
Cached:          1571552 kB
SwapCached:        14740 kB
Active:          1165488 kB
Inactive:         865688 kB
Active(anon):     202140 kB
Inactive(anon):   195580 kB
Active(file):     963348 kB
Inactive(file):   670108 kB
Unevictable:        5772 kB
Mlocked:            5772 kB
SwapTotal:       1048572 kB
SwapFree:         787780 kB
Dirty:                32 kB
Writeback:             0 kB
AnonPages:        383924 kB
Mapped:           248488 kB
Shmem:              6488 kB
Slab:             391060 kB
SReclaimable:     199712 kB
SUnreclaim:       191348 kB
KernelStack:       22640 kB
PageTables:        28056 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:     2973376 kB
Committed_AS:   42758232 kB
VmallocTotal:   258867136 kB
VmallocUsed:           0 kB
VmallocChunk:          0 kB
CmaTotal:        2093056 kB
CmaFree:           78916 kB

我沿用kernel document 的注釋:/kernel/Documentation/filesystems/proc.txt

  • MemTotal: Total usable ram (i.e. physical ram minus a few reserved bits and the kernel binary code)
    NHLOS = RAMsize - SystemRAM (/proc/iomem) 子系統(tǒng)占用內(nèi)存大小
    SystemRAM = MemTotal + Kernel Static
    可以通過讀取全局變量_totalram_pages獲取
    Kernel Static包括page struct和內(nèi)核基本組件初始化占用檩禾,拆解需要cmdline添加memblock=debug,抓開機log

  • MemFree: The sum of LowFree+HighFree
    讀取全局變量vm_zone_stat[NR_FREE_PAGES]獲取

  • MemAvailable: An estimate of how much memory is available for starting new applications, without swapping. Calculated from MemFree, SReclaimable, the size of the file LRU lists, and the low watermarks in each zone. The estimate takes into account that the system needs some page cache to function well, and that not all reclaimable
    slab will be reclaimable, due to items being in use. The impact of those factors will vary from system to system.
    通過page_alloc.c 中的si_mem_available()計算獲得

  • Buffers: Relatively temporary storage for raw disk blocks shouldn't get tremendously large (20MB or so)
    通過nr_blockdev_pages()計算

  • Cached: in-memory cache for files read from the disk (the pagecache). Doesn't include SwapCached。 Cached = NR_FILE_PAGES - swapcache -Buffers

  • SwapCached: Memory that once was swapped out, is swapped back in but still also is in the swapfile (if memory is needed it doesn't need to be swapped out AGAIN because it is already in the swapfile. This saves I/O)

  • Active: Memory that has been used more recently and usually not reclaimed unless absolutely necessary.

  • Inactive: Memory which has been less recently used. It is more eligible to be reclaimed for other purposes

  • Mlocked:不會被交換到交換分區(qū)的頁面淌实,通過vm_zone_stat[NR_MLOCK]計算

  • SwapTotal: total amount of swap space available

  • SwapFree: Memory which has been evicted from RAM, and is temporarily on the disk

  • Dirty: Memory which is waiting to get written back to the disk
    臟頁,vm_zone_stat[NR_FILE_DIRTY]計算

  • Writeback: Memory which is actively being written back to the disk
    正在回寫的頁面映皆,vm_zone_stat[NR_FILE_DIRTY]計算

  • AnonPages: Non-file backed pages mapped into userspace page tables
    通過vm_node_stat[NR_ANON_MAPPED]計算

  • AnonHugePages: Non-file backed huge pages mapped into userspace page tables

  • Mapped: files which have been mmaped, such as libraries
    統(tǒng)計所有映射到用戶空間的內(nèi)容緩存頁面访敌,vm_node_stat[NR_FILE_MAPPED]

  • Shmem: vm_node_stat[NR_SHMEM]

  • Slab: in-kernel data structures cache

  • SReclaimable: Part of Slab, that might be reclaimed, such as caches
    NR_SLAB_RECLAIMABLE

  • SUnreclaim: Part of Slab, that cannot be reclaimed on memory pressure
    NR_SLAB_UNRECLAIMABLE

  • PageTables: amount of memory dedicated to the lowest level of page tables.
    vm_zone_stat[NR_PAGETABLE]

  • KernelStack: vm_zone_stat[NR_KERNEL_STACK_KB]

  • NFS_Unstable: NFS pages sent to the server, but not yet committed to stable storage
    在NFS中凉敲,發(fā)送到服務(wù)端但沒有寫入磁盤的頁面,NR_UNSTABLE_NFS

  • Bounce: Memory used for block device "bounce buffers"

  • WritebackTmp: Memory used by FUSE for temporary writeback buffers

  • CommitLimit: Based on the overcommit ratio ('vm.overcommit_ratio'),

            this is the total amount of  memory currently available to
            be allocated on the system. This limit is only adhered to
            if strict overcommit accounting is enabled (mode 2 in
            'vm.overcommit_memory').
            The CommitLimit is calculated with the following formula:
            CommitLimit = ([total RAM pages] - [total huge TLB pages]) *
                           overcommit_ratio / 100 + [total swap pages]
            For example, on a system with 1G of physical RAM and 7G
            of swap with a `vm.overcommit_ratio` of 30 it would
            yield a CommitLimit of 7.3G.
            For more details, see the memory overcommit documentation
            in vm/overcommit-accounting.
    
  • Committed_AS: The amount of memory presently allocated on the system.

            The committed memory is a sum of all of the memory which
            has been allocated by processes, even if it has not been
            "used" by them as of yet. A process which malloc()'s 1G
            of memory, but only touches 300M of it will show up as
        using 1G. This 1G is memory which has been "committed" to
            by the VM and can be used at any time by the allocating
            application. With strict overcommit enabled on the system
            (mode 2 in 'vm.overcommit_memory'),allocations which would
            exceed the CommitLimit (detailed above) will not be permitted.
            This is useful if one needs to guarantee that processes will
            not fail due to lack of memory once that memory has been
            successfully allocated.
    
  • VmallocTotal: total size of vmalloc memory area

  • VmallocUsed: amount of vmalloc area which is used

  • VmallocChunk: largest contiguous block of vmalloc area which is free

我們可以得到一些大體的"等式".

  1. MemAvailable = free - kernel reserved memory + ative file + inactive file + SReclaimable - 2 * zone low water mark

  2. Cached = All file page - buffers - swapping = Active file + Inactive file + Unevictable file - Buffers

  3. Slab = SReclaimable + SUnreclaimable

  4. Active = Active(anon) + Active(file)

  5. Inactive = Inactive(anon) + Inactive(file)

  6. AnonPages + Buffers + Cached = Active + Inactive

  7. Buffers + Cached = Active(file) + Inactive(file)

  8. SwapTotal = SwapFree + SwapUsed(Not SwapCached)

  9. KernelStack = the number of kernel task * Stack Size(16K) 算線程數(shù)非常有用

  10. Kernel Memory Usage = KernelStack + SUnreclaim+ PageTables + Shmem + Vmalloc

  11. Native Memory Usage = Mapped + AnonPages + Others

(2). Android dumpsys meminfo 解析.

從Android 的角度, Google 提供了dumpsys meminfo 命令來獲取全局以及某個進(jìn)程的memory 信息.

android 在 AativityManagerService 里面提供了一個meminfo 的service , 可以來抓取process 的memory 使用概要, 這個慢慢成為了android 上層判斷的主流.

adb shell dumpsys meminfo ==> dump 全局的memory 使用情況.

adb shell dumpsys meminfo pid ==> dump 單個process memory 使用情況.

它的一個好處在于, 如果是user build 沒有root 權(quán)限的時候, 可以借道sh ==> system_server ==> binder ==> process 進(jìn)行抓取操作, 規(guī)避了權(quán)限方面的風(fēng)險. 看不懂嘿嘿

對應(yīng)的完整操作命令:

 OP46E7:/ # dumpsys meminfo -h

meminfo dump options: [-a] [-d] [-c] [-s] [--oom] [process]

  -a: include all available information for each process.

  -d: include dalvik details.

  -c: dump in a compact machine-parseable representation.

  -s: dump only summary of application memory usage.

  -S: dump also SwapPss.

  --oom: only show processes organized by oom adj.

  --local: only collect details locally, don't call process.

  --package: interpret process arg as package, dumping all

             processes that have loaded that package.

  --checkin: dump data for a checkin

  --proto: dump data to proto

If [process] is specified it can be the name or

pid of a specific process to dump.

下面我們將解析dumpsys meminfo 的數(shù)據(jù)來源, 便于大家讀懂.

(2.1) 系統(tǒng)memory 來源解析.

 Total RAM: 3,849,612K (status moderate)

 Free RAM: 1,870,085K (   74,389K cached pss + 1,599,904K cached kernel +   195,792K free)

 Used RAM: 1,496,457K (  969,513K used pss +   526,944K kernel)

 Lost RAM:   686,331K

     ZRAM:    48,332K physical used for   260,604K in swap (1,048,572K total swap)

   Tuning: 384 (large 512), oom   322,560K, restore limit   107,520K (high-end-gfx)

Total RAM: /proc/meminfo->MemTotal

Free RAM: cached pss = All pss of process oom_score_adj >= 900 優(yōu)先級大于900進(jìn)程pss

       cached kernel = /proc/meminfo.Buffers + /proc/meminfo.Cached + /proc/meminfo.SlabReclaimable- /proc/meminfo.Mapped

       free = /proc/meminfo.MemFree

Used RAM: used pss: total pss - cached pss

Kernel: /proc/meminfo.Shmem + /proc/meminfo.SlabUnreclaim + VmallocUsed + /proc/meminfo.PageTables + /proc/meminfo.KernelStack

Lost RAM: /proc/meminfo.memtotal - (totalPss - totalSwapPss) - /proc/meminfo.memfree - /proc/meminfo.cached - kernel used - zram used

(2.2) 單個Process 數(shù)據(jù)源解析

單個process 則通過binder 接入app 來抓取. 接到ActivityThread 的 dumpMeminfo 來統(tǒng)計.

Native Heap, 從jemalloc 取出,對應(yīng)實現(xiàn)是 android_os_Debug_getNativeHeapSize() ==> mallinfo() ==> jemalloc

Dalvik Heap, 使用Runtime 從java heap 取出.

同時根據(jù)process 的smaps 解析數(shù)據(jù) Pss Private Dirty Private Clean SwapPss.

 ** MEMINFO in pid 1138 [system] **

                   Pss  Private  Private  SwapPss     Heap     Heap     Heap

                 Total    Dirty    Clean    Dirty     Size    Alloc     Free

                ------   ------   ------   ------   ------   ------   ------

  Native Heap    62318    62256        0        0   137216    62748    74467

  Dalvik Heap    21549    21512        0        0    28644    16356    12288

 Dalvik Other     4387     4384        0        0

        Stack       84       84        0        0

       Ashmem      914      884        0        0

    Other dev      105        0       56        0

     .so mmap    10995     1112     4576        0

    .apk mmap     3912        0     2776        0

    .ttf mmap       20        0        0        0

    .dex mmap    60297       76    57824        0

    .oat mmap     2257        0       88        0

    .art mmap     3220     2788       12        0

   Other mmap     1944        4      672        0

    GL mtrack     5338     5338        0        0

      Unknown     3606     3604        0        0

        TOTAL   180946   102042    66004        0   165860    79104    86755

 App Summary

                       Pss(KB)

                        ------

           Java Heap:    24312

         Native Heap:    62256

                Code:    66452

               Stack:       84

            Graphics:     5338

       Private Other:     9604

              System:    12900

               TOTAL:   180946       TOTAL SWAP PSS:        0

 Objects

               Views:       11         ViewRootImpl:        2

         AppContexts:       20           Activities:        0

              Assets:       15        AssetManagers:        0

       Local Binders:      528        Proxy Binders:     1134

       Parcel memory:      351         Parcel count:      370

    Death Recipients:      627      OpenSSL Sockets:        0

            WebViews:        0

 SQL

         MEMORY_USED:      384

  PAGECACHE_OVERFLOW:       86          MALLOC_SIZE:      117

 DATABASES

      pgsz     dbsz   Lookaside(b)          cache  Dbname

         4       64             85        12/29/8  /data/system_de/0/accounts_de.db

         4       40                         0/0/0    (attached) ceDb: /data/system_ce/0/accounts_ce.db

         4       20             27        54/17/3  /data/system/notification_log.db

解釋一下:

        Java Heap:    24312  dalvik heap + .art mmap

     Native Heap:    62256    

            Code:    66452    .so mmap + .jar mmap + .apk mmap + .ttf mmap + .dex mmap + .oat mmap

           Stack:       84

        Graphics:     5338    Gfx dev + EGL mtrack + GL mtrack

   Private Other:     9604  TotalPrivateClean + TotalPrivateDirty - java - native - code - stack - graphics

          System:    12900    TotalPss - TotalPrivateClean - TotalPrivateDirty

下面的解釋來源于 https://developer.android.com/studio/profile/investigate-ram?hl=zh-cn

Dalvik Heap

您的應(yīng)用中 Dalvik 分配占用的 RAM寺旺。Pss Total 包括所有 Zygote 分配(如上述 PSS 定義所述爷抓,通過進(jìn)程之間的共享內(nèi)存量來衡量)。Private Dirty 數(shù)值是僅分配到您應(yīng)用的堆的實際 RAM阻塑,由您自己的分配和任何 Zygote 分配頁組成蓝撇,這些分配頁自從 Zygote 派生應(yīng)用進(jìn)程以來已被修改。

Heap Alloc 是 Dalvik 和原生堆分配器為您的應(yīng)用跟蹤的內(nèi)存量陈莽。此值大于 Pss Total 和 Private Dirty渤昌,因為您的進(jìn)程從 Zygote 派生虽抄,且包含您的進(jìn)程與所有其他進(jìn)程共享的分配。

.so mmap 和 .dex mmap

映射的 .so(原生)和 .dex(Dalvik 或 ART)代碼占用的 RAM独柑。Pss Total 數(shù)值包括應(yīng)用之間共享的平臺代碼迈窟;Private Clean 是您的應(yīng)用自己的代碼。通常情況下忌栅,實際映射的內(nèi)存更大 - 此處的 RAM 僅為應(yīng)用執(zhí)行的代碼當(dāng)前所需的 RAM车酣。不過,.so mmap 具有較大的私有臟 RAM索绪,因為在加載到其最終地址時對原生代碼進(jìn)行了修改湖员。

.oat mmap

這是代碼映像占用的 RAM 量,根據(jù)多個應(yīng)用通常使用的預(yù)加載類計算瑞驱。此映像在所有應(yīng)用之間共享娘摔,不受特定應(yīng)用影響。

.art mmap

這是堆映像占用的 RAM 量唤反,根據(jù)多個應(yīng)用通常使用的預(yù)加載類計算凳寺。此映像在所有應(yīng)用之間共享,不受特定應(yīng)用影響拴袭。盡管 ART 映像包含 Object 實例读第,它仍然不會計入您的堆大小。

(3). 內(nèi)存使用情況監(jiān)測

我們說通常的監(jiān)測機制有兩種. 一種是輪詢, 周期性的查看memory 的使用情況, 通常是通過腳本或者daemon 程序周期性的監(jiān)測. 監(jiān)測的數(shù)據(jù)一般包括:

/proc/meminfo 系統(tǒng)總的memory 使用情況.

/proc/zoneinfo 每個zone 的memory 使用情況.

/proc/buddyinfo buddy system 的memory 情況.

/proc/slabinfo slub 的memory 使用分布.

/proc/vmallocinfo vmalloc 的memory 使用情況.

/proc/swaps zram 的使用情況, 以及占用memory 情況.

/proc/mtk_memcfg/slabtrace slab memory 的具體分布. 確認(rèn)現(xiàn)在已經(jīng)沒有了

/proc/vmstat 系統(tǒng)memory 根據(jù)使用類型的分布.

/sys/kernel/debug/ion/ion_mm_heap mtk multi-media ion memory 使用情況. debug需要另外打開了

/sys/kernel/debug/ion/client_history ion 各個clients 使用的ion 情況粗略統(tǒng)計.

/proc/mali/memory_usage arm mali gpu 使用memory 按進(jìn)程統(tǒng)計 沒有找到mali

/sys/kernel/debug/mali0/gpu_memory arm mali gpu 使用memory 按進(jìn)程統(tǒng)計

ps -A -T 打印系統(tǒng)所有進(jìn)程/線程資訊, 可觀察每個進(jìn)程的線程量, 以及VSS/RSS

dumpsys meminfo 從Android 角度觀察系統(tǒng)memory 的使用情況.

/sys/kernel/debug/mlog mtk 統(tǒng)計系統(tǒng)一段時間(約60s) 系統(tǒng)memory的使用情況, 包括kernel, user space, ion, gpu 等的分布.

大家可以寫腳本周期性的抓取.

這里單獨把mlog 抓出來說明, mlog 是MTK 開發(fā)的輕量級的memory log, 一體式抓取常見的memory 統(tǒng)計資訊, 包括kernel(vmalloc, slub...), user space (進(jìn)程VSS,RSS...), ion, gpu 等在一段時間內(nèi)部的概要使用情況. 并且提供了圖形化的tool 來展示具體的memory 分布, 使用情況, 非常方便, 請大家優(yōu)先使用(tool_for_memory_analysis).

另外一種熔斷, 即限制memory 的使用, 當(dāng)?shù)揭欢ǔ潭葧r, 主動發(fā)生異常, 回報錯誤.

通常情況下, 系統(tǒng)memory leaks , 就會伴隨OOM 發(fā)生, 嚴(yán)重是直接KE. 而單個進(jìn)程 memory leaks, 如果它的oom adj < 0, 即daemon service 或者 persist app, 通常它的memory leaks 也會觸發(fā)系統(tǒng)OOM , 因為lmk 難以殺掉. 如果是普通app 發(fā)生memory leaks, 則往往直接被LMK 殺掉. 難以對系統(tǒng)產(chǎn)生直接異常. 當(dāng)然進(jìn)程也可能無法申請到memory 發(fā)生JE, NE 等異常.

針對總的系統(tǒng)的memory 使用, 我們可以通過設(shè)定, 限制系統(tǒng)總體的memory, 比如設(shè)置系統(tǒng)最大2GB:

(1). ProjectConfig.mk

CUSTOM_CONFIG_MAX_DRAM_SIZE = 0x80000000

注意: CUSTOM_CONFIG_MAX_DRAM_SIZE must be included by AUTO_ADD_GLOBAL_DEFINE_BY_NAME_VALUE

(2). preloader project config file

vendor/mediatek/proprietary/bootable/bootloader/preloader/custom/{project}/{project}.mk

CUSTOM_CONFIG_MAX_DRAM_SIZE = 0x80000000

注意: CUSTOM_CONFIG_MAX_DRAM_SIZE must be exported

針對某個進(jìn)程使用的memory, 我們可以通過setrlimit 來進(jìn)行限制, 如: 針對camerahalserver, 使用init 的setrlimit 進(jìn)行限制.

service camerahalserver /vendor/bin/hw/camerahalserver

class main

user cameraserver

group audio camera input drmrpc sdcard_rw system media graphics

ioprio rt 4

capabilities SYS_NICE

writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks

#limit VSS to 4GB

rlimit as 0x100000000 0x100000000

#limit malloc to 1GB

rlimit data 0x40000000 0x40000000

把camerahalserver 的VSS 限制到4GB, 把malloc 的大小限制到1GB, 一旦超出就會返回 ENOMEM, 通常情況下拥刻,這樣可自動產(chǎn)生NE. 以便抓到camerahalserver 的更多信息.

注意的是因為vendor 下面的service 是由 vendor_init 拉起來的, 需要給vendor_init 設(shè)置sepolicy. 以免無法設(shè)定成功.

/device/mediatek/sepolicy/basic/non_plat/vendor_init.te

allow vendor_init self:global_capability_class_set sys_resource;

也可以直接在代碼里面寫死, 參考如/frameworks/av/media/libmedia/MediaUtils.cpp

針對APP java heap的memory leaks, 我們可以通過設(shè)定 dalvik 的heap size 進(jìn)行限制, 通過system property 設(shè)定, 注意的是, 目前的做法會影響到所有的java process.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市父泳,隨后出現(xiàn)的幾起案子般哼,更是在濱河造成了極大的恐慌,老刑警劉巖惠窄,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蒸眠,死亡現(xiàn)場離奇詭異,居然都是意外死亡杆融,警方通過查閱死者的電腦和手機楞卡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來脾歇,“玉大人蒋腮,你說我怎么就攤上這事∨焊鳎” “怎么了池摧?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長激况。 經(jīng)常有香客問我作彤,道長膘魄,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任竭讳,我火速辦了婚禮创葡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘绢慢。我一直安慰自己蹈丸,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布呐芥。 她就那樣靜靜地躺著逻杖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪思瘟。 梳的紋絲不亂的頭發(fā)上荸百,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天,我揣著相機與錄音滨攻,去河邊找鬼够话。 笑死,一個胖子當(dāng)著我的面吹牛光绕,可吹牛的內(nèi)容都是我干的女嘲。 我是一名探鬼主播,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼诞帐,長吁一口氣:“原來是場噩夢啊……” “哼欣尼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起停蕉,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤愕鼓,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后慧起,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體菇晃,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年蚓挤,在試婚紗的時候發(fā)現(xiàn)自己被綠了磺送。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡灿意,死狀恐怖估灿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情脾歧,我是刑警寧澤甲捏,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站鞭执,受9級特大地震影響司顿,放射性物質(zhì)發(fā)生泄漏芒粹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一大溜、第九天 我趴在偏房一處隱蔽的房頂上張望化漆。 院中可真熱鬧,春花似錦钦奋、人聲如沸座云。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽朦拖。三九已至,卻和暖如春厌衔,著一層夾襖步出監(jiān)牢的瞬間璧帝,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工富寿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留睬隶,地道東北人。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓页徐,卻偏偏與公主長得像苏潜,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子变勇,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,960評論 2 355

推薦閱讀更多精彩內(nèi)容