- 一:App內(nèi)存組成以及限制
- 二:什么是OOM打厘?
- 三:Android 內(nèi)存分析命令介紹
- 四,內(nèi)存三大問題
- 五,MAT工具(查找具體內(nèi)存泄漏點(diǎn)的)
- 六秫逝, LeakCanary
- 七:Android內(nèi)存泄漏常見場景以及解決方案
- 八:Bitmap (解決這個(gè)基本是99%的解決)
- 九:總體思想
一:App內(nèi)存組成以及限制
Android給每個(gè)APP分配一個(gè)VM,讓App運(yùn)行在dalvik上恕出,這樣app奔潰了也不會(huì)影響系統(tǒng)。系統(tǒng)給VM 分配了一定的內(nèi)存大小违帆,如果應(yīng)用超過了vm最大內(nèi)存浙巫,就會(huì)出現(xiàn)
內(nèi)存溢出 crash;
由程序控制操作的內(nèi)存空間在heap上 分java heapsize 和 native heapsize
java申請的內(nèi)存在vm heap 上 所有如果java申請的內(nèi)存大小超過了vm邏輯內(nèi)存限制就會(huì)內(nèi)存溢出的異常;
native 層 內(nèi)存申請不受器限制 native層 native process 對內(nèi)存帶下的限制;
二:什么是OOM刷后?
1的畴,強(qiáng)引用,軟引用尝胆,弱引用,虛引用的區(qū)別;
軟引用內(nèi)存不足的時(shí)候才會(huì)回收丧裁,弱引用,gc掃描到了就會(huì)回收含衔;虛引用相當(dāng)于沒有引用;
三:Android 內(nèi)存分析命令介紹
常用的內(nèi)存調(diào)優(yōu)分析命令:
- dumpsys meminfo
- procrank
- cat /proc/meminfo
- free
- showmap
- vmstat
四,內(nèi)存三大問題
1煎娇,內(nèi)存抖動(dòng)
內(nèi)存波動(dòng)圖形呈鋸齒狀,GC導(dǎo)致卡頓; 比如贪染,自定view的時(shí)候缓呛,在ondraw等地方頻繁創(chuàng)建對象,系統(tǒng)無連續(xù)可用的內(nèi)存空間杭隙,就頻繁GC哟绊,導(dǎo)致卡頓;
2痰憎,內(nèi)存泄漏
在當(dāng)前應(yīng)用周期內(nèi)不再使用的對象被GC roots引用票髓,導(dǎo)致不能回收,使實(shí)際可用內(nèi)存變行攀狻炬称;
3,內(nèi)存溢出
即OOM涡拘,OOM時(shí)會(huì)導(dǎo)致程序異常玲躯,Android設(shè)備出廠以后,java虛擬機(jī)對單個(gè)應(yīng)用的最大內(nèi)存分配就確定下來了,超過這個(gè)值就會(huì)OOM;
OOM時(shí)不時(shí)一定代表內(nèi)存不夠了嗎跷车?
(1)Java堆內(nèi)存溢出棘利,
(2)無足夠連續(xù)內(nèi)存空間(整體加起來夠可是,無連續(xù)的),
(3)FD數(shù)量超過限制(fd文件句柄)
(4)線程數(shù)量超出限制(每個(gè)應(yīng)用的線程數(shù)是有限制的朽缴,小于1000個(gè)善玫,這種情況可以用線程池,業(yè)務(wù)有問題密强,都1000個(gè)線程了)茅郎,
(5)虛擬內(nèi)存不足
五,MAT工具(查找具體內(nèi)存泄漏點(diǎn)的)
六或渤, 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、資源性對象未關(guān)閉
對于資源性對象不再使用時(shí)池磁,應(yīng)該立即調(diào)用它的close()函數(shù)奔害,將其關(guān)閉,然后再置為null地熄。例如Bitmap等資源未關(guān)閉會(huì)造成內(nèi)存泄漏华临,此時(shí)我們應(yīng)該在Activity銷毀時(shí)及時(shí)關(guān)閉。
2离斩、注冊對象未注銷
例如BraodcastReceiver银舱、EventBus未注銷造成的內(nèi)存泄漏,我們應(yīng)該在Activity銷毀時(shí)及時(shí)注銷跛梗。
3、類的靜態(tài)變量持有大數(shù)據(jù)對象
盡量避免使用靜態(tài)變量存儲(chǔ)數(shù)據(jù)棋弥,特別是大數(shù)據(jù)對象核偿,建議使用數(shù)據(jù)庫存儲(chǔ)。
4顽染、單例造成的內(nèi)存泄漏
優(yōu)先使用Application的Context漾岳,如需使用Activity的Context,可以在傳入Context時(shí)使用弱引用進(jìn)行封裝粉寞,然后尼荆,在使用到的地方從弱引用中獲取Context,如果獲取不到唧垦,則直接return即可捅儒。
5、非靜態(tài)內(nèi)部類的靜態(tài)實(shí)例
該實(shí)例的生命周期和應(yīng)用一樣長,這就導(dǎo)致該靜態(tài)實(shí)例一直持有該Activity的引用巧还,Activity的內(nèi)存資源不能正潮廾В回收。此時(shí)麸祷,我們可以將該內(nèi)部類設(shè)為靜態(tài)內(nèi)部類或?qū)⒃搩?nèi)部類抽取出來封裝成一個(gè)單例澎怒,如果需要使用Context,盡量使用Application Context阶牍,如果需要使用Activity Context喷面,就記得用完后置空讓GC可以回收,否則還是會(huì)內(nèi)存泄漏走孽。
6惧辈、Handler臨時(shí)性內(nèi)存泄漏
在Queue中存在的時(shí)間過長,就會(huì)導(dǎo)致Handler無法被回收融求。如果Handler是非靜態(tài)的咬像,則會(huì)導(dǎo)致Activity或者Service不會(huì)被回收。并且消息隊(duì)列是在一個(gè)Looper線程中不斷地輪詢處理消息生宛,當(dāng)這個(gè)Activity退出時(shí)县昂,消息隊(duì)列中還有未處理的消息或者正在處理的消息,并且消息隊(duì)列中的Message持有Handler實(shí)例的引用陷舅,Handler又持有Activity的引用倒彰,所以導(dǎo)致該Activity的內(nèi)存資源無法及時(shí)回收,引發(fā)內(nèi)存泄漏莱睁。解決方案如下所示:
- 1待讳、使用一個(gè)靜態(tài)Handler內(nèi)部類,然后對Handler持有的對象(一般是Activity)使用弱引用仰剿,這樣在回收時(shí)创淡,也可以回收Handler持有的對象。
- 2南吮、在Activity的Destroy或者Stop時(shí)琳彩,應(yīng)該移除消息隊(duì)列中的消息,避免Looper線程的消息隊(duì)列中有待處理的消息需要處理部凑。
需要注意的是露乏,AsyncTask內(nèi)部也是Handler機(jī)制,同樣存在內(nèi)存泄漏風(fēng)險(xiǎn)涂邀,但其一般是臨時(shí)性的瘟仿。對于類似AsyncTask或是線程造成的內(nèi)存泄漏,我們也可以將AsyncTask和Runnable類獨(dú)立出來或者使用靜態(tài)內(nèi)部類比勉。
7劳较、容器中的對象沒清理造成的內(nèi)存泄漏
在退出程序之前驹止,將集合里的東西clear,然后置為null兴想,再退出程序
8幢哨、WebView
WebView都存在內(nèi)存泄漏的問題,在應(yīng)用中只要使用一次WebView嫂便,內(nèi)存就不會(huì)被釋放掉捞镰。我們可以為WebView開啟一個(gè)獨(dú)立的進(jìn)程,使用AIDL與應(yīng)用的主進(jìn)程進(jìn)行通信毙替,WebView所在的進(jìn)程可以根據(jù)業(yè)務(wù)的需要選擇合適的時(shí)機(jī)進(jìn)行銷毀岸售,達(dá)到正常釋放內(nèi)存的目的。
9厂画、使用ListView時(shí)造成的內(nèi)存泄漏
在構(gòu)造Adapter時(shí)凸丸,使用緩存的convertView。
八:Bitmap (解決這個(gè)基本是99%的解決)
http://www.reibang.com/p/59cb10228f6c
九:總體思想
1袱院,設(shè)備分級(jí)
2.Bitmap優(yōu)化
統(tǒng)一圖片庫
線上線下監(jiān)控 hook
glide:官方推薦