性能優(yōu)化-內(nèi)存優(yōu)化

\color{red}{聲明:內(nèi)容禁止轉(zhuǎn)載,總結來自享學課堂知識的搬運,一切為了查找資料的方便;}

  • 一:App內(nèi)存組成以及限制
  • 二:什么是OOM?
  • 三:Android 內(nèi)存分析命令介紹
  • 四,內(nèi)存三大問題
  • 五,MAT工具(查找具體內(nèi)存泄漏點的)
  • 六, LeakCanary
  • 七:Android內(nèi)存泄漏常見場景以及解決方案
  • 八:Bitmap (解決這個基本是99%的解決)
  • 九:總體思想

一:App內(nèi)存組成以及限制

Android給每個APP分配一個VM,讓App運行在dalvik上,這樣app奔潰了也不會影響系統(tǒng)。系統(tǒng)給VM 分配了一定的內(nèi)存大小,如果應用超過了vm最大內(nèi)存,就會出現(xiàn)
內(nèi)存溢出 crash;
由程序控制操作的內(nèi)存空間在heap上 分java heapsize 和 native heapsize
java申請的內(nèi)存在vm heap 上 所有如果java申請的內(nèi)存大小超過了vm邏輯內(nèi)存限制就會內(nèi)存溢出的異常;
native 層 內(nèi)存申請不受器限制 native層 native process 對內(nèi)存帶下的限制;

二:什么是OOM?

1,強引用,軟引用,弱引用,虛引用的區(qū)別;
軟引用內(nèi)存不足的時候才會回收,弱引用,gc掃描到了就會回收;虛引用相當于沒有引用;

三:Android 內(nèi)存分析命令介紹

常用的內(nèi)存調(diào)優(yōu)分析命令:

  1. dumpsys meminfo
  2. procrank
  3. cat /proc/meminfo
  4. free
  5. showmap
  6. vmstat

四,內(nèi)存三大問題

1,內(nèi)存抖動

內(nèi)存波動圖形呈鋸齒狀,GC導致卡頓; 比如,自定view的時候,在ondraw等地方頻繁創(chuàng)建對象,系統(tǒng)無連續(xù)可用的內(nèi)存空間,就頻繁GC,導致卡頓;

2,內(nèi)存泄漏

在當前應用周期內(nèi)不再使用的對象被GC roots引用,導致不能回收,使實際可用內(nèi)存變??;

3,內(nèi)存溢出

即OOM,OOM時會導致程序異常,Android設備出廠以后,java虛擬機對單個應用的最大內(nèi)存分配就確定下來了,超過這個值就會OOM;
OOM時不時一定代表內(nèi)存不夠了嗎?
(1)Java堆內(nèi)存溢出,
(2)無足夠連續(xù)內(nèi)存空間(整體加起來夠可是,無連續(xù)的),
(3)FD數(shù)量超過限制(fd文件句柄)
(4)線程數(shù)量超出限制(每個應用的線程數(shù)是有限制的,小于1000個,這種情況可以用線程池,業(yè)務有問題,都1000個線程了),
(5)虛擬內(nèi)存不足

五,MAT工具(查找具體內(nèi)存泄漏點的)

六, LeakCanary

https://github.com/square/leakcanary

1, LeakCanary是如何安裝的?

  • 注冊app:contentprovider contentprovider.oncreate 比 application.oncreate 更先執(zhí)行
  • 2,apk 打包流程 mergeAndroidManifest.xml -> app AndroidManifest

2, LeakCanary檢測Activity退出的原理

1,ActivityLifecycleCallbacks 生命周期回調(diào)去檢測
2,Reference弱引用 Reference弱Queue

七:Android內(nèi)存泄漏常見場景以及解決方案

1、資源性對象未關閉

對于資源性對象不再使用時,應該立即調(diào)用它的close()函數(shù),將其關閉,然后再置為null。例如Bitmap等資源未關閉會造成內(nèi)存泄漏,此時我們應該在Activity銷毀時及時關閉。

2、注冊對象未注銷

例如BraodcastReceiver、EventBus未注銷造成的內(nèi)存泄漏,我們應該在Activity銷毀時及時注銷。

3、類的靜態(tài)變量持有大數(shù)據(jù)對象

盡量避免使用靜態(tài)變量存儲數(shù)據(jù),特別是大數(shù)據(jù)對象,建議使用數(shù)據(jù)庫存儲。

4、單例造成的內(nèi)存泄漏

優(yōu)先使用Application的Context,如需使用Activity的Context,可以在傳入Context時使用弱引用進行封裝,然后,在使用到的地方從弱引用中獲取Context,如果獲取不到,則直接return即可。

5、非靜態(tài)內(nèi)部類的靜態(tài)實例

該實例的生命周期和應用一樣長,這就導致該靜態(tài)實例一直持有該Activity的引用,Activity的內(nèi)存資源不能正常回收。此時,我們可以將該內(nèi)部類設為靜態(tài)內(nèi)部類或?qū)⒃搩?nèi)部類抽取出來封裝成一個單例,如果需要使用Context,盡量使用Application Context,如果需要使用Activity Context,就記得用完后置空讓GC可以回收,否則還是會內(nèi)存泄漏。

6、Handler臨時性內(nèi)存泄漏

在Queue中存在的時間過長,就會導致Handler無法被回收。如果Handler是非靜態(tài)的,則會導致Activity或者Service不會被回收。并且消息隊列是在一個Looper線程中不斷地輪詢處理消息,當這個Activity退出時,消息隊列中還有未處理的消息或者正在處理的消息,并且消息隊列中的Message持有Handler實例的引用,Handler又持有Activity的引用,所以導致該Activity的內(nèi)存資源無法及時回收,引發(fā)內(nèi)存泄漏。解決方案如下所示:

  • 1、使用一個靜態(tài)Handler內(nèi)部類,然后對Handler持有的對象(一般是Activity)使用弱引用,這樣在回收時,也可以回收Handler持有的對象。
  • 2、在Activity的Destroy或者Stop時,應該移除消息隊列中的消息,避免Looper線程的消息隊列中有待處理的消息需要處理。

需要注意的是,AsyncTask內(nèi)部也是Handler機制,同樣存在內(nèi)存泄漏風險,但其一般是臨時性的。對于類似AsyncTask或是線程造成的內(nèi)存泄漏,我們也可以將AsyncTask和Runnable類獨立出來或者使用靜態(tài)內(nèi)部類。

7、容器中的對象沒清理造成的內(nèi)存泄漏

在退出程序之前,將集合里的東西clear,然后置為null,再退出程序

8、WebView

WebView都存在內(nèi)存泄漏的問題,在應用中只要使用一次WebView,內(nèi)存就不會被釋放掉。我們可以為WebView開啟一個獨立的進程,使用AIDL與應用的主進程進行通信,WebView所在的進程可以根據(jù)業(yè)務的需要選擇合適的時機進行銷毀,達到正常釋放內(nèi)存的目的。

9、使用ListView時造成的內(nèi)存泄漏

在構造Adapter時,使用緩存的convertView。

八:Bitmap (解決這個基本是99%的解決)

http://www.itdecent.cn/p/59cb10228f6c

九:總體思想

1,設備分級

2.Bitmap優(yōu)化

統(tǒng)一圖片庫

線上線下監(jiān)控 hook

glide:官方推薦

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容