Android常見的內(nèi)存泄漏和優(yōu)化方案

內(nèi)存泄漏

是指該被GC垃圾回收的宴杀,由于有另外一個對象仍然在引用它,導致無法回收蜗元,造成內(nèi)存泄漏或渤,過多的內(nèi)存泄漏會導致OOM。

不少人認為JAVA程序许帐,因為有垃圾回收機制劳坑,應該沒有內(nèi)存泄漏。我們已經(jīng)知道了成畦,如果某個對象距芬,從根節(jié)點可到達涝开,也就是存在從根節(jié)點到該對象的引用鏈,那么該對象是不會被 GC 回收的框仔。如果說這個對象已經(jīng)不會再被使用到了舀武,是無用的,我們依然持有他的引用的話离斩,就會造成內(nèi)存泄漏银舱,例如 一個長期在后臺運行的線程持有 Activity 的引用,這個時 候 Activity 執(zhí)行了 onDestroy 方法跛梗,那么這個 Activity 就是從根節(jié)點可到達并且無用的對象寻馏, 這個 Activity 對象就是泄漏的對象,給這個對象分配的內(nèi)存將無法被回收核偿。如果我們的java運行很久,而這種內(nèi)存泄漏不斷的發(fā)生诚欠,最后就沒內(nèi)存可用了。當然java的漾岳,內(nèi)存泄漏和C/C++是不一樣的轰绵。如果java程序完全結(jié)束后,它所有的對象就都不可達了尼荆,系統(tǒng)就可以對他們進行垃圾回收左腔,它的內(nèi)存泄漏僅僅限于它本身,而不會影響整個系統(tǒng)的捅儒。C/C++的內(nèi)存泄漏就比較糟糕了液样,它的內(nèi)存泄漏是系統(tǒng)級,即使該C/C++程序退出野芒,它泄漏的內(nèi)存也無法被系統(tǒng)回收蓄愁,永遠不可用了,除非重啟機器狞悲。

Android的一個應用程序的內(nèi)存泄漏對別的應用程序影響不大撮抓。為了能夠使得Android應用程序安全且快速的運行,Android的每個應用程序都會使用一個專有的Dalvik虛擬機實例來運行摇锋,它是由Zygote服務進程孵化出來的丹拯,也就是說每個應用程序都是在屬于自己的進程中運行的。Android為不同類型的進程分配了不同的內(nèi)存使用上限荸恕,如果程序在運行過程中出現(xiàn)了內(nèi)存泄漏的而造成應用進程使用的內(nèi)存超過了這個上限乖酬,則會被系統(tǒng)視為內(nèi)存泄漏,從而被kill掉融求,這使得僅僅自己的進程被kill掉咬像,而不會影響其他進程(如果是system_process等系統(tǒng)進程出問題的話,則會引起系統(tǒng)重啟)。


android常見內(nèi)存泄漏

1.Handler 引起的內(nèi)存泄漏

我們知道县昂,主線程的Looper對象不斷從消息隊列中取出消息肮柜,然后再交給Handler處理。如果在Activity中定義Handler對象倒彰,那么Handler肯定是持有Activty的引用审洞。而每個Message對象是持有Handler的引用的(Message對象的target屬性持有Handler引用),從而導致Message間接引用到了Activity待讳。如果在Activty destroy之后芒澜,消息隊列中還有Message對象,Activty是不會被回收的创淡。當然了痴晦,如果消息正在準備(處于延時入隊期間)放入到消息隊列中也是一樣的。

2.單例模式引起的內(nèi)存泄漏

單例模式在Android開發(fā)中會經(jīng)常用到辩昆,但是如果使用不當就會導致內(nèi)存泄漏阅酪。因為單例的靜態(tài)特性使得它的生命周期同應用的生命周期一樣長旨袒,如果一個對象已經(jīng)沒有用處了汁针,但是單例還持有它的引用,那么在整個應用程序的生命周期它都不能正常被回收砚尽,從而導致內(nèi)存泄漏施无。

3.非靜態(tài)內(nèi)部類創(chuàng)建靜態(tài)實例引起的內(nèi)存泄漏

靜態(tài)變量存儲在方法區(qū),它的生命周期從類加載開始必孤,到整個進程結(jié)束猾骡。一旦靜態(tài)變量初始化后,它所持有的引用只有等到進程結(jié)束才會釋放敷搪。在Android開發(fā)中兴想,靜態(tài)持有很多時候都有可能因為其使用的生命周期不一致而導致內(nèi)存泄漏,所以我們在新建靜態(tài)持有的變量的時候需要多考慮一下各個成員之間的引用關系赡勘,并且盡量少地使用靜態(tài)持有的變量嫂便,以避免發(fā)生內(nèi)存泄漏。當然闸与,我們也可以在適當?shù)臅r候講靜態(tài)量重置為null毙替,使其不再持有引用,這樣也可以避免內(nèi)存泄漏践樱。

4.非靜態(tài)匿名內(nèi)部類引起的內(nèi)存泄漏

非靜態(tài)內(nèi)部類厂画、匿名內(nèi)部類 都會持有外部類的一個引用,如果有一個靜態(tài)變量引用了非靜態(tài)內(nèi)部類或者匿名內(nèi)部類拷邢,導致非靜態(tài)內(nèi)部類或者匿名內(nèi)部類的生命周期比外部類(Activity)長袱院,就會導致外部類在該被回收的時候,無法被回收掉,引起內(nèi)存泄漏, 除非外部類被卸載(JVM自帶的類加載器所加載的類忽洛,在虛擬機的生命周期中抛人,始終不會被卸載,除非使用自定義的類加載器脐瑰,感興趣的同學可以研究一下)妖枚。

5.注冊/反注冊未成對使用引起的內(nèi)存泄漏

在andorid開發(fā)中,我們經(jīng)常會在Activity的onCreate中注冊廣播接受器苍在、EventBus等绝页,如果忘記成對的使用反注冊,可能會引起內(nèi)存泄漏寂恬。開發(fā)過程中應該養(yǎng)成良好的相關续誉,在onCreate或onResume中注冊,要記得相應的在onDestroy或onPause中反注冊初肉。

6.資源對象沒有關閉引起的內(nèi)存泄漏

當我們打開資源時酷鸦,一般都會使用緩存。比如讀寫文件資源牙咏、打開數(shù)據(jù)庫資源臼隔、使用Bitmap資源等等。當我們不再使用時妄壶,應該關閉它們摔握,使得緩存內(nèi)存區(qū)域及時回收。雖然有些對象丁寄,如果我們不去關閉氨淌,它自己在finalize()函數(shù)中會自行關閉。但是這得等到GC回收時才關閉伊磺,這樣會導致緩存駐留一段時間盛正。如果我們頻繁的打開資源,內(nèi)存泄漏帶來的影響就比較明顯了屑埋。

7.集合對象沒有及時清理引起的內(nèi)存泄漏

我們通常會把一些對象裝入到集合中豪筝,當不使用的時候一定要記得及時清理集合,讓相關對象不再被引用雀彼。如果集合是static壤蚜、不斷的往里面添加東西、又忘記去清理徊哑,肯定會引起內(nèi)存泄漏袜刷。


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

1、Handler持有的引用最好使用弱引用莺丑,在Activity被釋放的時候要記得清空Message著蟹,取消Handler對象的Runnable墩蔓;

2、非靜態(tài)內(nèi)部類萧豆、非靜態(tài)匿名內(nèi)部類會自動持有外部類的引用奸披,為避免內(nèi)存泄露,可以考慮把內(nèi)部類聲明為靜態(tài)的涮雷;

3阵面、對于生命周期比Activity長的對象,要避免直接引用Activity的context洪鸭,可以考慮使用ApplicationContext样刷;?

4、廣播接收器览爵、EventBus等的使用過程中置鼻,注冊/反注冊應該成對使用;

5蜓竹、不再使用的資源對象Cursor箕母、File、Bitmap等要記住正確關閉俱济;?

6嘶是、集合里面的東西、有加入就應該對應有相應的刪除


如何檢查和分析內(nèi)存泄漏

因為內(nèi)存泄漏是在堆內(nèi)存中姨蝴,所以對我們來說并不是可見的俊啼。通常我們可以借助MAT、LeakCanary等工具來檢測應用程序是否存在內(nèi)存泄漏左医。

1、MAT是一款強大的內(nèi)存分析工具同木,功能繁多而復雜浮梢。

2.使用 LeakCanary 檢測Android 的內(nèi)存泄漏。

內(nèi)存泄漏防不勝防彤路,通過LeakCanary工具秕硝,我們能在開發(fā)測試階段發(fā)現(xiàn)絕大多數(shù)的內(nèi)存泄漏。這個工具是開源的洲尊,使用也非常方便远豺,而且能夠相對準確定位出是哪里出現(xiàn)內(nèi)存泄漏。

3.? 通過Android Studio 自帶的工具 Android Profilter 找到MEMORY這個欄目 進行檢測坞嘀。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末躯护,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子丽涩,更是在濱河造成了極大的恐慌棺滞,老刑警劉巖裁蚁,帶你破解...
    沈念sama閱讀 222,729評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異继准,居然都是意外死亡枉证,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評論 3 399
  • 文/潘曉璐 我一進店門移必,熙熙樓的掌柜王于貴愁眉苦臉地迎上來室谚,“玉大人,你說我怎么就攤上這事崔泵∥杼眩” “怎么了?”我有些...
    開封第一講書人閱讀 169,461評論 0 362
  • 文/不壞的土叔 我叫張陵管削,是天一觀的道長倒脓。 經(jīng)常有香客問我,道長含思,這世上最難降的妖魔是什么崎弃? 我笑而不...
    開封第一講書人閱讀 60,135評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮含潘,結(jié)果婚禮上饲做,老公的妹妹穿的比我還像新娘。我一直安慰自己遏弱,他們只是感情好盆均,可當我...
    茶點故事閱讀 69,130評論 6 398
  • 文/花漫 我一把揭開白布在扰。 她就那樣靜靜地躺著陷揪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪削祈。 梳的紋絲不亂的頭發(fā)上饰抒,一...
    開封第一講書人閱讀 52,736評論 1 312
  • 那天肮砾,我揣著相機與錄音,去河邊找鬼袋坑。 笑死仗处,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的枣宫。 我是一名探鬼主播婆誓,決...
    沈念sama閱讀 41,179評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼也颤!你這毒婦竟也來了洋幻?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,124評論 0 277
  • 序言:老撾萬榮一對情侶失蹤歇拆,失蹤者是張志新(化名)和其女友劉穎鞋屈,沒想到半個月后范咨,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,657評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡厂庇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,723評論 3 342
  • 正文 我和宋清朗相戀三年渠啊,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片权旷。...
    茶點故事閱讀 40,872評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡替蛉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出拄氯,到底是詐尸還是另有隱情躲查,我是刑警寧澤,帶...
    沈念sama閱讀 36,533評論 5 351
  • 正文 年R本政府宣布译柏,位于F島的核電站镣煮,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏鄙麦。R本人自食惡果不足惜典唇,卻給世界環(huán)境...
    茶點故事閱讀 42,213評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望胯府。 院中可真熱鬧介衔,春花似錦、人聲如沸骂因。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寒波。三九已至乘盼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間影所,已是汗流浹背蹦肴。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留猴娩,地道東北人。 一個月前我還...
    沈念sama閱讀 49,304評論 3 379
  • 正文 我出身青樓勺阐,卻偏偏與公主長得像卷中,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子渊抽,可洞房花燭夜當晚...
    茶點故事閱讀 45,876評論 2 361

推薦閱讀更多精彩內(nèi)容