移動App 性能優(yōu)化評測以及優(yōu)化讀書筆記1---降低待機內存

1.1 內存分析常用工具

1.Android studio 自帶memery Profile 進行內存觀察,這樣可以看到內存的消耗量,如果存在明顯的內存泄漏,隨著功能的反復使用,內存會出現不斷升高,即使出現GC也沒法降下來.可以進行錄制,保存hprof文件.

2.使用SDK自帶的Android Device Monitor,觀察Heap堆的內存變化,配合Cause GC 按鈕進行觀察頁面的內存動態(tài)值,遇到可疑的內存泄漏進行保存hprof .

3.收集到內存數據采用eclipse Memory Analyzer Tool (MAT)來分析.

使用MAT分析的一些技巧:

  • 通常先使用Android SDK 提供的hprof-conv 轉換工具,把hprof 轉換成為去除系統(tǒng)內存使用的內存,而只留下應用代碼分配的內存數據來分析.(hprof-conv 工具在Android SDK/platformtools/)
    hprof-conv -z <infile><outfile>

  • 可以使用OQL進行篩選 : select * from instanceof java.long.Object s where s.@objectAddress>1107296256

image.png

1.2規(guī)范測試流程以及常見問題

1.2.1測試流程

1.代碼:

盡量保證內存測試代碼是純凈版本,不應該附加多余的Log和調試組件的,把測試的代碼全部關閉.因為這些代碼可能會臨時分配內存,引起更多的GC,導致應用出現運行緩慢,卡頓現象.

2.測試場景:

測試場景有兩類:1)屬于新增功能或改動某項功能,需要對該功能進行性能測試.

2)整體性能測試.

各類場景測試的 重點:

  • 包含圖片顯示的界面

  • 網絡傳輸的大量數據

  • 需要緩存數據的場景

場景轉換成用例

  • 多張圖片的前臺進程

  • 多個場景來回切換

  • 長時間運行進程的內存增長

1.1.2 Dalvik Heap的常見問題

常見問題一般有下面幾種:

  • 隨著功能反復的執(zhí)行,heap內存一直在持續(xù)增長.這種情況一般出現內存泄漏,此時最合適使用LeakCanary 等工具進行白盒測試kk

  • 代碼執(zhí)行是出現頻繁的GC,Heap Alloc 內存大幅度波動.這種情況通常是分配了許多臨時變量或數組,隨后有迅速回收.確定具體的 場景后可以使用Heap Viewer/Allocation Tracker查看具體分配情況.

  • 每次啟動應用,Heap內存相比以前版本穩(wěn)定增長.一般由于App待機或者使用某項功能后,可能是由于新功能引入的固定內存增長. 可以采用HeapDump 后對比多版本或功能的前后對比,找到原因.

  • Heap Alloc變化不大,但是進程Dalvik Heap Pss(Proportional Set Size)內存明顯增加.是由于分配了大量小對象找出內存碎片.

1.2.4新的問題特殊的情況

注意,Heap 內存并不是應用的全部,我們在設置或者其他管理工具看到的內存大小是整個應用的全部進行內存使用量.有可能是出現在Heap部分完全沒有增長,而其他部分有增長情況.

adb shell dumpsys meminfo com.xiu.app

image.png

Andorid studio 工具查看的內存是HeapAlloc的大小,而從上圖可以看出 HeapAlloc 和Dalvik Heap大小不一樣,除了DalvikHeap 之外還有其他部分會消耗內存.

可以進行對各個部分的PPS 進行分析.

1.2.5 進一步挖掘Dalvik Heap內存

對于簡單的問題無法回答內存遞增的情況下,例如

“這個版本引入了一個簡單的庫,內存就漲了20M”

“這些代碼只是初始化了幾個對象,還沒開始用呢”

“一行代碼都沒改,怎么會漲呢?”

通過分析,無法正常解答時需要更深入底層DVM (Dalvik Virtual Memory)機制

1.2.6 Dalvik Heap 內存機制

Dalvik 內存分配源碼 dalvik/vm/alloc ,具體的內部機制:

  1. DVM使用mmap 系統(tǒng)調用從系統(tǒng)分配大塊內存作為java heap.根據機制,如果分類的內存尚未真正使用,就不計入privateDirty 和pss.一般處于shareDirty共享內存.

  2. 新鍵對象后,由于需要向地址寫數據,一般是分配一個4KB的物理內存頁面

  3. 在運行過程中會執(zhí)行GC,有些可以回收,有些一直存在

  4. 在GC 過程中有可能會觸發(fā)TrimHeap,即釋放空閑內存表現為PrivateDirty/Pss下降.

頁面利用率:

頁面利用率問題?(碎片問題)

由于內存分配的時候,開始會分配的比較滿,經過GC后,大部分內存釋放,但是有少部分留下來了.在這種情況下會產生問題,整頁的4KB內存中可能只有一個小對象,但是在統(tǒng)計PrivateDirty/Pss是還是按4KB計算.主要原因是DVM在進行內存回收的時候是采用Mark-Sweep 方式而不是Compating GC,并沒有對對象進行移動,造成內存碎片(內存空洞).

分析:

用MAT 導出csv 格式.

可以把對象按照內存地址(取高位地址&0xfffff000)分布,相同高位的對象處于相同的頁面.可以得出柱狀分布圖.通過對比觀察,如果發(fā)現 柱狀短的數量多(說明頁面利用率低的很多),這樣就說明小對象碎片比較嚴重.

經驗總結:

內存分配的最小單位是頁面,通常4KB

對于開發(fā)人員,盡量不要在循環(huán)中創(chuàng)建很多臨時變量.

可以將大型的循環(huán)拆散,分段或者按需執(zhí)行.

1.4 進階 內存原理

對于緩存的策略,不能簡單粗暴的將所有的緩存一次生成,這樣會導致大量的碎片,需要一種合適的策略來生成.

使用adb shell dumpsys meminfo com.xiu.app

總結規(guī)律如下:

通常大致了解到.Dalvik Other 和Mmap 和代碼數量有關,對于越復雜的應用,這部分內存就越多.

現在需要了解背后的原理.

1.4.1 從物理內存到應用

由于linux的的底層內存分配和共享機制,android 也是符合這一原則.在Ashmem以及COW(Copy -On-Write)的機制基礎上,Android進程最明顯的內存特征是與zygote共享內存.因為Android進程是用zygote fork出來的,所以Android的虛擬機和Zygote進行共享,應用只需要載入自己的Dalvik字節(jié)碼及資源既可以開始工作.

綜上所述,一個在運行Android應用進程會包含以下幾部分:

  • Dalvik虛擬機代碼(共享內存)

  • 應用框架的代碼(共享內存)

  • 應用框架的資源(共享內存)

  • 應用框架的so庫(共享內存)

  • 應用代碼(私有內存)

  • 應用的資源(私有內存)

  • 應用的so庫(私有內存)

  • 堆內存,其他部分(共享/私有內存)

下面是dumpsys meminfo工具的詳細統(tǒng)計各部分內存值:

1.4.3 smaps

由于android 是基于linux 內核,進程內存信息和linux是一致,所以Dalvik heap之外的信息都可以在/proc/<pid>/smaps中取得.

用ps 命令可以查看 linux 系統(tǒng)下所有進程信息.

image.png

Annroid 中ps命令參數:-t -x,-p,-P,-c [pid|name]-t顯示進程下的線程列表-x 顯示進程耗費的用戶時間和系統(tǒng)時間,單位s-P 顯示調度策略叛赚,通過是bg or fg 匪煌,當獲取失敗將會un和er比之前打印的內容多出了一列PCY,表示進程的調度等級

  1. image.png

PID:進程號 PPID:父進程號 VSIZE :進程的虛擬內存大小 RSS :進程分配到的屋里內存大小 WCHAN:程正在睡眠的內核函數名稱裆悄;該函數的名稱是從/root/system.map文件中獲得的 NAME :進程名

通過dumpsys meminfo com.xiu.app

image.png

dumpsys 統(tǒng)計的各個內存塊的pss,shared_dirty,private_dirty,按照以下的原則進行歸類:

  • /dev/ashmem/dalvik-heap 和/dev/ashmem/dalvik-zygote ==>Dalvik Heap

  • 其他以/dev/ashmem/dalvik- 開頭的區(qū)域 ==> Dalvik Other

  • /dev/Ashmem 下所有不以dalvik- 開頭的區(qū)域 ==>Ashmem

  • /dev下的其他內存區(qū)域 ==>Other dev

  • ,如[stack],[malloc],Unknown等 ==>其他部分

Dalvik :

在上述我們直到Dalvik 包括Dalvik heap,和Dalvik other.

Dalvik heap : Dalvik-heap 和Dalvik-zygote .堆內存,所有的java對象實例都放在這里.

Dalvik Other :

*LinearAlloc

*Accounting

*Code_Cache

1.LinearAlloc 包括 dalvik-LinearAlloc.線性分配器,虛擬機存放載入類的函數信息,隨著dex數量增加而增加,注明的 65535個函數的限制就是從這里來的.

  1. Accounting 包括 /dev/ashmem/dalvik-aux-structure,/dev/ashmem/dalvik-bitmap-2,/dev/ashmem/dalvik-card-table .這些主要是作為標記和指針表使用. Dalvik-aux-structure隨類及方法數增大而增加,dalvik-bitmap 隨著dalvik-heap 增大而增大.

3.Code_cache 包括/dev/ashmem/dalvik-jit-code-cache .jit編譯代碼后的緩存,隨著代碼復雜度增加而變大.

因為堆內部的內存分配往往是應用消耗內存最多的地方,所以有效的方法就是減少Dalvik-heap中的創(chuàng)建對象,減少代碼量.

由于這部分的內存增長取決與代碼復雜度,因此通常情況下沒有簡單直接的方法降低他們內存的消耗.

mmap

系統(tǒng)會將一些文件mmap到內存中,對各個文件進行mmap的時機以大小比較復雜,dex_mmap 是主要的內容.

1.4.3 zygote 共享內存機制

對于meminfo 輸出的Heap Size/alloc /Free 部分的數值,這些數值是Dalvik 虛擬機統(tǒng)計的內存堆的使用量,但是這些值是如何對應到Pss內存中,以及Heap Alloc 和Heap Pss 相差不遠,但是又不一樣.他們之間的關系如下:

Heap Alloc統(tǒng)計是由虛擬機分配的所有應用實例的內存,所以會把應用從zygote共享的部分也算進去,于是Heap Alloc的值總是比實際物理內存使用值要大.

Pss表示進程的實際使用物理內存.是有私有內存+共享內存的按比例分到的值.

Dalvik Pss=Private dirty+(Shared Dirty/共享內存進程數)

1.4.4 多進程應用

當一個進程結束后他所占用的共享庫內存將會被其他仍然使用的進程所分擔,共享庫消耗的物理內存并不會減少.實際上對所有共享使用了這個庫的應用,Pss都會增加,因為分擔的共享內存增加了.對于一般的應用只共享了zygote 進程的Android框架等基礎部分,通常手機使用的進程樹達到幾十 至上百個.所以某個進程結束后,其他進程內存增加的情況并不明顯.

但是對于多進程的應用來說,由于多進程之間會共享很多內容,包括代碼,資源,so庫 等,因此單個進程結束后對其他進程影響比較明顯.

由此可見,在統(tǒng)計多進程應用內存優(yōu)化時候需要綜合考慮,以免優(yōu)化了一個進程內存,卻造成其他進程的內存增長.

1.5 案例: 優(yōu)化dex 相關內存

Dalvik Mmap 和Dalvik Other會隨著代碼復雜度增加而增大.而這兩部分的內存將接近總內存的一半.在對Dalvik Heap做了優(yōu)化之后,繼續(xù)研究這部分內存有何優(yōu)化.

Dalvik Other存放的是類的數據結構和關系.而Dalvik mmap是類的函數代碼和常亮.通常情況下,減少這部分內存,需要精簡代碼,精簡無用代碼,或者將功能插件化.如果深入理解系統(tǒng)還有其他的方法降低這部分內存消耗.

1.5.1 從class 對象說起

1.5.2一個類的內存消耗

首先在代碼中使用一個類,例如一下代碼:

Foo f=new Foo();

虛擬機在執(zhí)行到這步時會做什么呢?

第一步:loadClass ,將類信息從dex文件加載內存:

1)讀取.dex mmap中class對應的數據

2)分配Native-heap和dalvik-heap內存創(chuàng)建class對象

3)分配dalvik-LinearAlloc存放class數據

4)分配dalvik-aux-structure存放class數據

第二步 new instance ,創(chuàng)建對象實例

1)執(zhí)行 .dex mmap中<clinit> 和<init>代碼

2)分配dalvik-heap 創(chuàng)建class實例

計算下new 操作需要消耗的內存:

1.5.3 dex mmap

dex mmap 在android的作用是映射classes.dex文件Dalvik虛擬機需要從dex文件中加載類信息\字符串常量,還需要在調用函數時候直接從mmap內存中讀取函數代碼來執(zhí)行,所以該部分內存是程序運行必不可少的.

在一個實例,可以發(fā)現dex 的文件排列順序導致內存有可能被浪費.原因是因為dex文件在生成是是按字母順序排列的,由于4KB頁面加載的原因,實際運行是會加載許多相鄰的但不會被用到的數據.例如在代碼中用了A1類,虛擬機需要加載包含A1類的數據頁面,但由于A1只有1KB,那么加載的4KB頁面中還會有A2,A3,A4類,總共占4KB內存.

假設我們的代碼中在用到A1類后,還會用到B1,C1,D1 類,那么如果能在dex文件中將A1,B1,C1,D1的類放在一起,虛擬機只需要加載 一個4kB頁面,不僅減少了內存使用,對程序運行的速度也有好處.因此調整的思路就是優(yōu)化dex文件的數據的順序,將能夠用到的數據緊密排列在一起.

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末矛纹,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子光稼,更是在濱河造成了極大的恐慌或南,老刑警劉巖孩等,帶你破解...
    沈念sama閱讀 212,029評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異采够,居然都是意外死亡肄方,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 90,395評論 3 385
  • 文/潘曉璐 我一進店門蹬癌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來权她,“玉大人,你說我怎么就攤上這事逝薪∮缫” “怎么了?”我有些...
    開封第一講書人閱讀 157,570評論 0 348
  • 文/不壞的土叔 我叫張陵董济,是天一觀的道長步清。 經常有香客問我,道長虏肾,這世上最難降的妖魔是什么尼啡? 我笑而不...
    開封第一講書人閱讀 56,535評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮询微,結果婚禮上崖瞭,老公的妹妹穿的比我還像新娘。我一直安慰自己撑毛,他們只是感情好书聚,可當我...
    茶點故事閱讀 65,650評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著藻雌,像睡著了一般雌续。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上胯杭,一...
    開封第一講書人閱讀 49,850評論 1 290
  • 那天驯杜,我揣著相機與錄音,去河邊找鬼做个。 笑死鸽心,一個胖子當著我的面吹牛,可吹牛的內容都是我干的居暖。 我是一名探鬼主播顽频,決...
    沈念sama閱讀 39,006評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼太闺!你這毒婦竟也來了糯景?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,747評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蟀淮,沒想到半個月后最住,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 44,207評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡怠惶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,536評論 2 327
  • 正文 我和宋清朗相戀三年涨缚,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片甚疟。...
    茶點故事閱讀 38,683評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡仗岖,死狀恐怖逃延,靈堂內的尸體忽然破棺而出览妖,到底是詐尸還是另有隱情,我是刑警寧澤揽祥,帶...
    沈念sama閱讀 34,342評論 4 330
  • 正文 年R本政府宣布讽膏,位于F島的核電站,受9級特大地震影響拄丰,放射性物質發(fā)生泄漏府树。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,964評論 3 315
  • 文/蒙蒙 一料按、第九天 我趴在偏房一處隱蔽的房頂上張望奄侠。 院中可真熱鬧,春花似錦载矿、人聲如沸垄潮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽弯洗。三九已至,卻和暖如春逢勾,著一層夾襖步出監(jiān)牢的瞬間牡整,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評論 1 266
  • 我被黑心中介騙來泰國打工溺拱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留逃贝,地道東北人。 一個月前我還...
    沈念sama閱讀 46,401評論 2 360
  • 正文 我出身青樓迫摔,卻偏偏與公主長得像秋泳,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子攒菠,可洞房花燭夜當晚...
    茶點故事閱讀 43,566評論 2 349

推薦閱讀更多精彩內容