Android 內(nèi)存之監(jiān)控篇

一蚯妇、前言

內(nèi)存問題主要會造成如下幾個影響。第一暂筝、會發(fā)生OOM等異常箩言,因?yàn)槊總€對象都會占用一定的內(nèi)存,內(nèi)存過多會影響對象的分配失敗焕襟,嚴(yán)重者會導(dǎo)致設(shè)備重啟陨收。第二、內(nèi)存過大鸵赖,導(dǎo)致系統(tǒng)回收緩存內(nèi)存务漩,以及會加快GC頻率,從而導(dǎo)致應(yīng)用卡頓它褪。

內(nèi)存的監(jiān)控就尤為的重要饵骨。下面從幾個方面來看Android對內(nèi)存的監(jiān)控,從而有助于觀察內(nèi)存變化茫打。

二居触、free

free是輕量級的查看設(shè)備整體內(nèi)存情況,具體例子如下:

root@debian7:/proc/10# free
             total       used       free     shared    buffers     cached
Mem:       3044840     247692    2797148          0      19896     110084
-/+ buffers/cache:     117712    2927128
Swap:       901116          0     901116

其中total = used + free包吝,單位KB饼煞。
對于-/+ buffers/cache行,是從有無緩沖來看诗越。117712 = used - buffers - cached.
2927128 = free + buffers + cached.

三、/proc/meminfo文件

/proc/meminfo是free的加強(qiáng)版息堂,free中的數(shù)據(jù)也是從/proc/meminfo而來的嚷狞。

root@debian7:/proc/10# cat /proc/meminfo
MemTotal:        3044840 kB  // RAM內(nèi)存總大小
MemFree:         2797520 kB  // RAM可用內(nèi)存大小
Buffers:           19912 kB  // Buffers緩存,文件緩存
Cached:           110084 kB  // Cached緩存大小
SwapCached:            0 kB
Active:            97184 kB // 在活躍下的緩沖或高速緩沖存儲器頁面文件的大小
Inactive:          94008 kB // 非活躍下的緩沖或高速緩沖存儲器頁面文件的大小
Active(anon):      61312 kB // Active = Active(anon) + Active(file)
Inactive(anon):     6008 kB
Active(file):      35872 kB
Inactive(file):    88000 kB
Unevictable:           0 kB
Mlocked:               0 kB
SwapTotal:        901116 kB
SwapFree:         901116 kB
Dirty:                 0 kB // 等待被寫回到磁盤的內(nèi)存大小荣堰。
Writeback:             0 kB // 正在被寫回到磁盤的內(nèi)存大小床未。
AnonPages:         61188 kB
Mapped:            24656 kB // 文件通過mmap分配的內(nèi)存
Shmem:              6132 kB
Slab:              20412 kB //  內(nèi)核數(shù)據(jù)結(jié)構(gòu)緩存的大小。Linux中的Slab內(nèi)存分配策略振坚,相對于伙伴系統(tǒng)分配
SReclaimable:       6288 kB
SUnreclaim:        14124 kB
KernelStack:        1000 kB
PageTables:         4656 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:     2423536 kB
Committed_AS:     535828 kB
VmallocTotal:   34359738367 kB  // 總分配的虛擬地址空間
VmallocUsed:      158760 kB  // 已分配的虛擬地址空間
VmallocChunk:   34359576572 kB
HardwareCorrupted:     0 kB
AnonHugePages:         0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
DirectMap4k:       45056 kB
DirectMap2M:     2076672 kB
DirectMap1G:     1048576 kB

四薇搁、vmstat

vmstat命令可以查看內(nèi)存、IO和CPU等信息渡八。

語法命令:

Usage: vmstat [ -n iterations ] [ -d delay ] [ -r header_repeat ]
    -n iterations     數(shù)據(jù)循環(huán)輸出的次數(shù)
    -d delay          兩次數(shù)據(jù)間的延遲時長(單位:S)
    -r header_repeat  循環(huán)多少次啃洋,再輸出一次頭信息行

vmstat例子:

root@debian7:/proc/10# vmstat
procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa
 0  0      0 2797396  19960 110084    0    0     1     0   13   25  0  0 100  0

procs 程序

  • r : 運(yùn)行的進(jìn)程數(shù)量
  • b :等待IO阻塞的進(jìn)程數(shù)量

memory 內(nèi)存

  • swpd : 虛擬內(nèi)存(swap空間)已使用的大小
  • free :剩余的物理內(nèi)存大小
  • buff : buff緩存大小
  • cache :文件等cache大小

swap swap空間传货,內(nèi)存夠用時,si和so值都為0

  • si : swap空間寫入內(nèi)存的數(shù)據(jù)量宏娄;
  • so: 內(nèi)存寫入swap空間的數(shù)據(jù)量问裕;

IO

  • bi : 每秒從塊設(shè)備讀取塊的數(shù)量
  • bo:每秒向塊設(shè)備寫入的塊數(shù)量

system

  • in : 每秒的中斷次數(shù)
  • cs :等秒的上下文切換次數(shù)

cpu

  • us : 用戶態(tài)執(zhí)行時間
  • sy : 內(nèi)核態(tài)執(zhí)行時間
  • id : 空閑時間(包括IO等待時間)
  • wa : 等待IO時間

五、/proc/[PID]/status

root@p212:/data/dropbear # cat /proc/4943/status
Name:   XXXXX
State:  S (sleeping) : 狀態(tài)
Tgid:   4943 :線程組ID
Pid:    4943 :進(jìn)程ID孵坚,同TGID粮宛,說明是主線程
PPid:   3769 :父進(jìn)程ID
TracerPid:      0
Uid:    10039   10039   10039   10039
Gid:    10039   10039   10039   10039
Ngid:   0
FDSize: 64 :FDSize是當(dāng)前分配過的文件描述符數(shù)量
Groups: 3003 9997 50039 : groups表示啟動這個進(jìn)程的用戶所在的組.
VmPeak:  1503968 kB :當(dāng)前進(jìn)程運(yùn)行過程中占用內(nèi)存的峰值
VmSize:   878224 kB  :虛擬內(nèi)存大小
VmLck:         0 kB
VmPin:         0 kB
VmHWM:     40040 kB :分配到物理內(nèi)存的峰值
VmRSS:     38120 kB : 虛擬內(nèi)存駐留集合大小
VmData:   134084 kB :進(jìn)程數(shù)據(jù)段的大小
VmStk:      8196 kB : 進(jìn)程堆棧段的大小
VmExe:        20 kB
VmLib:     69224 kB
VmPTE:       440 kB
VmSwap:        0 kB : 進(jìn)程占用Swap的大小.
Threads:        22 :線程數(shù)量
SigQ:   0/2462
SigPnd: 0000000000000000 : 存儲了該線程的待處理信號
ShdPnd: 0000000000000000 : 存儲了該線程組的待處理信號
SigBlk: 0000000000001204 : 存放被阻塞的信號
SigIgn: 0000000000000000 : 存放可被忽略的信號
SigCgt: 00000002000094f8
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000000000000000
Seccomp:        0
Cpus_allowed:   f
Cpus_allowed_list:      0-3
voluntary_ctxt_switches:        358 : 進(jìn)程主動切換上下文的次數(shù)(資源得不到等)
nonvoluntary_ctxt_switches:     400 : 進(jìn)程被動切換上下文的次數(shù).

六、Android#Runtime

Android中提供了一些接口卖宠,供使用者調(diào)用巍杈,可定時的采集以下幾種內(nèi)存情況,從而判斷當(dāng)前進(jìn)程內(nèi)存情況扛伍。

        Runtime runtime = Runtime.getRuntime();
        long javaMax = runtime.maxMemory();  //  JVM可分配的最大內(nèi)存
        long javaTotal = runtime.totalMemory();  //  當(dāng)前分配的內(nèi)存
        long javaUsed = javaTotal - runtime.freeMemory();  //  當(dāng)前使用的內(nèi)存
        
        float proportion = (float) javaUsed / javaMax;
        Log.e("TAG", "onResume: javaMax="+javaMax+";javaTotal="+javaTotal+";javaUsed="+javaUsed+";proportion="+proportion);

七秉氧、Android#onLowMemory

在Android4.0中提供了一些監(jiān)聽內(nèi)存的接口OnLowMemory和onTrimMemory

【一】、OnLowMemory

OnLowMemory是ComponentCallbacks接口中的方法蜒秤,當(dāng)系統(tǒng)內(nèi)存不足汁咏,要被殺死后臺程序時,會調(diào)用該方法作媚。

可用在Application攘滩、Activity、Fragement纸泡、Service和ContentProvider中

【二】漂问、onTrimMemory

因?yàn)镺nLowMemory的接口太簡單了,并沒有提供內(nèi)存的狀態(tài)女揭,在ComponentCallbacks2中豐富了回調(diào)了接口蚤假。

public interface ComponentCallbacks2 extends ComponentCallbacks {

    /** @hide */
    @IntDef(prefix = { "TRIM_MEMORY_" }, value = {
            TRIM_MEMORY_COMPLETE,
            TRIM_MEMORY_MODERATE,
            TRIM_MEMORY_BACKGROUND,
            TRIM_MEMORY_UI_HIDDEN,
            TRIM_MEMORY_RUNNING_CRITICAL,
            TRIM_MEMORY_RUNNING_LOW,
            TRIM_MEMORY_RUNNING_MODERATE,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface TrimMemoryLevel {}

    static final int TRIM_MEMORY_COMPLETE = 80;
    
    static final int TRIM_MEMORY_MODERATE = 60;
   
    static final int TRIM_MEMORY_BACKGROUND = 40;
    
    static final int TRIM_MEMORY_UI_HIDDEN = 20;

    static final int TRIM_MEMORY_RUNNING_CRITICAL = 15;

    static final int TRIM_MEMORY_RUNNING_LOW = 10;

    static final int TRIM_MEMORY_RUNNING_MODERATE = 5;

    void onTrimMemory(@TrimMemoryLevel int level);
}

同onLowMemory一致,也可用在Application吧兔、Activity磷仰、Fragement、Service和ContentProvider中境蔼。

  • TRIM_MEMORY_COMPLETE:內(nèi)存不足灶平,并且該進(jìn)程在后臺進(jìn)程列表最后一個,馬上就要被清理
  • TRIM_MEMORY_MODERATE:內(nèi)存不足箍土,并且該進(jìn)程在后臺進(jìn)程列表的中部逢享。
  • TRIM_MEMORY_BACKGROUND:內(nèi)存不足,并且該進(jìn)程是后臺進(jìn)程吴藻。
  • TRIM_MEMORY_UI_HIDDEN:內(nèi)存不足瞒爬,并且該進(jìn)程的UI已經(jīng)不可見了。
  • TRIM_MEMORY_RUNNING_CRITICAL:內(nèi)存不足,并且該進(jìn)程不是消耗性的后臺進(jìn)程侧但,需要清理內(nèi)存
  • TRIM_MEMORY_RUNNING_LOW:內(nèi)存不足矢空,并且該進(jìn)程不是消耗性的后臺進(jìn)程,需要清理內(nèi)存
  • TRIM_MEMORY_RUNNING_MODERATE:內(nèi)存不足俊犯,并且該進(jìn)程不是消耗性的后臺進(jìn)程妇多,需要清理內(nèi)存

八、dumpsys

通過adb shell dumpsys meminfo [pid | 包名] 可以查看單個APP內(nèi)存情況

如下:

Applications Memory Usage (kB):
Uptime: 31564143 Realtime: 31564143

** MEMINFO in pid 30712 [XXX] **
                   Pss  Private  Private  Swapped     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------
  Native Heap     2196     2092        0        0     6144     4855     1288
  Dalvik Heap     1517     1396        0        0     3873     2449     1424
 Dalvik Other      373      372        0        0
        Stack      132      132        0        0
       Ashmem        2        0        0        0
    Other dev        5        0        4        0
     .so mmap     1148       96      156        0
    .apk mmap      326        0       28        0
    .ttf mmap       88        0       76        0
    .dex mmap     2844        4     2840        0
    .oat mmap     1204        0      164        0
    .art mmap     1321      476      368        0
   Other mmap       11        8        0        0
    GL mtrack     2960     2960        0        0
      Unknown      121      120        0        0
        TOTAL    14248     7656     3636        0    10017     7304     2712

 App Summary
                       Pss(KB)
                        ------
           Java Heap:     2240
         Native Heap:     2092
                Code:     3364
               Stack:      132
            Graphics:     2960
       Private Other:      504
              System:     2956

               TOTAL:    14248      TOTAL SWAP (KB):        0

 Objects
               Views:       15         ViewRootImpl:        1
         AppContexts:        2           Activities:        1
              Assets:        2        AssetManagers:        2
       Local Binders:        9        Proxy Binders:       12
       Parcel memory:        3         Parcel count:       14
    Death Recipients:        0      OpenSSL Sockets:        0

 SQL
         MEMORY_USED:        0
  PAGECACHE_OVERFLOW:        0          MALLOC_SIZE:        0

第一部分主要字段解析:
  • Native Heap : Native堆大小
  • Dalvik Heap : java堆大小
  • Stack :棧大小
  • Ashmem : 匿名共享內(nèi)存大小
  • .so mmap : 映射的so庫大小
  • .apk mmap:apk占用內(nèi)存大小
  • .dex mmap : dex占用內(nèi)存大小
  • Pss Total :物理內(nèi)存總大小
  • Private Dirty : 進(jìn)程私有的內(nèi)存燕侠,相對磁盤數(shù)據(jù)有改動的內(nèi)存
  • Private Clean : 進(jìn)程私有的內(nèi)存者祖,相對磁盤數(shù)據(jù)沒有修改的內(nèi)存
  • Heap Size : Dalvik中,同runtime.totalMemory()
  • Heap Alloc : Dalvik中绢彤,同runtime.totalMemory()-runtime.freeMemory()
  • Heap Free : Dalvik中七问,同runtime.freeMemory()
App Summary主要字段解析:
  • Java Heap : Dalvik Heap 中的 Private Dirty + .art mmap 的 Private Dirty + Private Clean
  • Native Heap :Native Heap
  • Code : .so mmap+ .jar mmap + .apk mmap + .ttf mmap + .dex mmap + .oat mmap的 Private Dirty + Private Clean
  • Stack :Stack
Objects主要字段解析:
  • Views :存活的view的個數(shù)
  • ViewRootImpl : 存活的ViewRootImpl數(shù)量
  • AppContexts :APP整個上下文數(shù)量
  • Activities : 存活的Activity數(shù)量
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市茫舶,隨后出現(xiàn)的幾起案子械巡,更是在濱河造成了極大的恐慌,老刑警劉巖饶氏,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件讥耗,死亡現(xiàn)場離奇詭異,居然都是意外死亡疹启,警方通過查閱死者的電腦和手機(jī)古程,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來喊崖,“玉大人挣磨,你說我怎么就攤上這事』缍” “怎么了茁裙?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長节仿。 經(jīng)常有香客問我晤锥,道長,這世上最難降的妖魔是什么粟耻? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任查近,我火速辦了婚禮,結(jié)果婚禮上挤忙,老公的妹妹穿的比我還像新娘。我一直安慰自己谈喳,他們只是感情好册烈,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般赏僧。 火紅的嫁衣襯著肌膚如雪大猛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天淀零,我揣著相機(jī)與錄音挽绩,去河邊找鬼。 笑死驾中,一個胖子當(dāng)著我的面吹牛唉堪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播肩民,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼唠亚,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了持痰?” 一聲冷哼從身側(cè)響起灶搜,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎工窍,沒想到半個月后割卖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡患雏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年鹏溯,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纵苛。...
    茶點(diǎn)故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡剿涮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出攻人,到底是詐尸還是另有隱情取试,我是刑警寧澤,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布怀吻,位于F島的核電站瞬浓,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蓬坡。R本人自食惡果不足惜猿棉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望屑咳。 院中可真熱鬧萨赁,春花似錦、人聲如沸兆龙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至慰安,卻和暖如春腋寨,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背化焕。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工萄窜, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人撒桨。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓查刻,卻偏偏與公主長得像,于是被迫代替她去往敵國和親元莫。 傳聞我的和親對象是個殘疾皇子赖阻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評論 2 354