Android應用的內存優化總結

一、Android內存管理機制

1、Java對象的生命週期

Java對象的生命週期經歷7個階段,分別是創建階段、應用階段、不可見階段、不可達階段、收集階段、終結階段、對象控件重新分配階段。

2、內存回收機制

內存的三個區域

內存會有三個區域,Yong Generation(年輕代)、Old Generation(年老代)、permanent Generation(持久代)。
其中年輕代裏面又分爲三個區,eden、S0、S1。

內存的處理過程:

1.對象創建後在Eden區域,

2.執行GC時,如果對象仍然存貨,則複製到S0區。

3.當S0區滿時,改區域存活對象將複製到S1區,然後S0清空,接下來S0和S1角色互換。

4.當第三部達到一定次數後,存活對象將被複制到Old Generation。

5.當這個對象在Old Generation區域挺溜的時間達到一定程度時,它會被移動到Old Generation,最後積累一定時間再移動到Permaent Generation區域,Permaent Generation區域也存放一些靜態文件。

GC回收的一些算法

Copying算法:掃描出存活的對象,並複製到一塊新的完全未使用的控件中,對應於Young Generation,就是在Eden、FromSpace或ToSpace之間copy。

標記算法:掃描出存活對象,然後再回收未標記的對象,回收後對空出的空間要麼合併,要麼標記出來便於下次分配,以減少內存碎片帶來的損耗。年老代對象存活時間較長較穩定,使用標記算法回收。

GC類型

1.kGcCauseForAlloc:在分配內存時內存不夠情況下引起的GC,這種情況下GC會stop World。Stop World 是由於併發GC時,其他線程都會停止。

2.kGcCauseBackground:當內存達到一定閾值的時候引發GC,這個時候是一個後臺GC,不會引起Stop World。

3.kGcCauseExplicit:顯示調用時進行的GC,如果ART打開了這個選項,在system.gc時會進行GC。

其他GC注意事項

1.儘量不去顯式調用 system.gc() 減少不必要的系統開銷,影響應用的流暢度。

2.儘量減少內存泄露,避免OOM。

二、Android內存泄露

1、什麼是內存泄露?

java對象有自己的生命週期,當這個對象不需要再使用時,應該完整地走完生命週期,但因爲某些原因,對象雖然已經不再使用,仍然在內存中並沒有結束整個生命週期,這就意味着這個對象已經泄露了。

GC會選擇一些還存活的對象作爲內存遍歷的根節點 GC Roots,通過對GC Roots的可達性來判斷是否需要回收。

Android系統虛擬機的垃圾回收是通過虛擬機GC機制來實現的。GC會選擇一些存活的對象作爲內存便利的跟節點GC Roots,通過判斷GC Roots的可達性來判斷是否需要回收,如上圖其中 1 2 3 4直接或間接被GC Roots引用鏈相連,這類對象被認爲還需要使用的對象,就不會被回收。5 6 7將會被回收。到那時這裏如果Object4 如果不需要使用的話這時候也不會被回收,就屬於內存泄露。

2、常見內存泄露場景以及注意事項

~ 資源型對象未關閉
~ 註冊對象未註銷
~ 類的靜態變量持有大數據對象 如bitmap
~ 費靜態內部類的靜態實例
~ Handler臨時性內存泄露
~ 容器中的對象沒有清理造成的內存泄露

3、內存泄露分析工具

leakcanary

三、常見注意事項避免內存消耗過多

1、AutoBoxing自動裝箱過程


Integer num=0;
for(int i=0;i<100;i++){
num+=i;
​​}​​

這段代碼每次循環,虛擬機都必須創建一個新的整數對象,並把它加到其他整數對象前面,創建一個新的整數對象,意味着要消耗更多性能。int只有4字節,而Integer對象有16字節。

2、內容複用

1、有效利用系統自帶資源。
2、視圖複用,如ViewHolder。
3、對象池。
4、Bitmap對象複用。

3、使用最優的數據類型

1、當對象的數目在1000以內且特別多訪問而刪除和插入不高的時候儘量用ArrayMap替代HashMap。
2、枚舉的最大優點是安全、易讀,但是內存消耗是定義常量的三倍以上。可以使用註解方式來檢查安全。
3、使用IntDef和StringDef檢查類型安全。
4、LruCache建議使用這個緩存機制,但是既不能分配太大,也不能分配太小。

4、圖片的內存優化

設置位圖規格,使用inSampleSize實現位圖縮放和壓縮。使用緩存機制等。

四、內存分析工具

1、Memory Monitor

這個是一個我們開發過程中很常用的內存、CPU、網絡的分析工具。
Memory Monitor界面視圖
界面很直觀,左上角有運行的機型和項目包名,然後最直觀的動態圖,分別是CPU、Memory、NetWork。點進去可以進入的Memory。
Memory Monitor的Memory局部視圖
這裏可以清晰的看到顏色對應區域佔用的內存大小。
Memory Monitor的Memory整體視圖
通過這兩張圖 內存的大部分信息都能查閱到。我們在操作APP加載圖片等操作時候能看到內存上升、和下降,如果操作APP後發現內存不會下降可能就是我們有些對象沒有及時釋放,也有可能導致內存泄露。
還有對應的模擬GC,查看時間段具體內存信息以及一段時間的內存追蹤等工具可以使用。可以定位到具體的代碼行。如下圖:
具體類詳細內存信息展示
這裏有一個Shallow size這個屬性的概念:
Shallow size就是對象本身佔用內存的大小,不包含其引用的對象。常規對象(非數組)的Shallow size有其成員變量的數量和類型決定。數組的shallow size有數組元素的類型(對象類型、基本類型)和數組長度決定。

2、Heap Viewrer

Heap Viewrer工具視圖界面
如果是Android Studio的話通過Tools->Android->Android Device Monitor找到這個工具。
進入後選擇運行APP的包名然後點擊update Heap按鈕,這時候會在每次gc時展示數據信息,也可以在後面手動GC,如果在操作頁面這時候可能會發現小卡頓,因爲在GC時,可能導致其他線程停止工作,這時可以清晰看到表中內存信息:
頭部總覽視圖:

標題 含義
Heap Size 堆棧分配給APP的內存大小。
Allocated 已分配使用的內存大小。
Free 空閒的內存大小。
%Used Allocated/Heap Size 的使用率。
Object 對象數量

下面詳情視圖:

標題 含義
free 空閒的對象
data object 數據對象,Java類類型對象,是最主要的觀察對象。
class object java類類型的引用對象。
1-byte array(byte[],boolean[]) 一字節的數組對象。
2-byte array(short[],char[]) 兩字節的數組對象。
4-byte array(object[],int[],float[]) 4字節的數組對象。
8-byte array(long[],double[]) 8字節的數組對象。
non-java object 非Java對象。

每個類型的數據值對應:

標題 含義
Count 數量
Total Size 總共佔用的內存的大小
Smallest 將對象佔用內存從小到大排列,排在第一個對象佔用內存大小
Largest 將對象佔用內存從小到大排列,排在最後一個對象佔用的內存大小。
Median 將對象佔用內存從小到大排列,排在總監的對象佔用的內存大小。
Average 平均值
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章