Android性能優(yōu)化-內(nèi)存泄漏的8個(gè)Case

1. 什么是內(nèi)存泄漏嘲碱?

JVM內(nèi)存管理


關(guān)于內(nèi)存泄漏我們要知道造成,JVM內(nèi)存分配的幾種策略趁餐。

  1. 靜態(tài)的

靜態(tài)的存儲(chǔ)區(qū),內(nèi)存在程序編譯的時(shí)候就已經(jīng)分配好了菇绵,這塊內(nèi)存在程序整個(gè)運(yùn)行期間都一直存在肄渗,它主要存放靜態(tài)數(shù)據(jù)、全局的static數(shù)據(jù)和一些常量咬最。

2.棧式的

在執(zhí)行方法時(shí)翎嫡,方法一些內(nèi)部變量的存儲(chǔ)都可以放在棧上面創(chuàng)建,方法執(zhí)行結(jié)束的時(shí)候這些存儲(chǔ)單元就會(huì)自動(dòng)被注釋掉永乌。棧 內(nèi)存包括分配的運(yùn)算速度很快惑申,因?yàn)閮?nèi)在在處理器里面。當(dāng)然容量有限铆遭,并且棧式一塊連續(xù)的內(nèi)存區(qū)域硝桩,大小是由操作系統(tǒng)決定的,他先進(jìn)后 出枚荣,進(jìn)出完成不會(huì)產(chǎn)生碎片碗脊,運(yùn)行效率高且穩(wěn)定

3.堆式的

也叫動(dòng)態(tài)內(nèi)存 。我們通常使用new 來申請(qǐng)分配一個(gè)內(nèi)存橄妆。這里也是我們討論內(nèi)存泄漏優(yōu)化的關(guān)鍵存儲(chǔ)區(qū)衙伶。GC會(huì)根據(jù)內(nèi)存的使用情況,對(duì)堆內(nèi)存里的垃圾內(nèi)存進(jìn)行回收害碾。

堆內(nèi)存是一塊不連續(xù)的內(nèi)存區(qū)域矢劲,如果頻繁地new/remove會(huì)造成大量的內(nèi)存碎片,GC頻繁的回收慌随,導(dǎo)致內(nèi)存抖動(dòng)芬沉,這也會(huì)消耗我們應(yīng)用的性能
我們知道可以調(diào)用 System.gc();進(jìn)行內(nèi)存回收,但是GC不一定會(huì)執(zhí)行阁猜。

面對(duì)GC的機(jī)制丸逸,我們是否無能為力?其實(shí)我們可以通過聲明一些引用標(biāo)記來讓GC更好對(duì)內(nèi)存進(jìn)行回收剃袍。

類型 回收時(shí)機(jī) 生命周期
StrongReference (強(qiáng)引用) 任何時(shí)候GC是不能回收他的黄刚,哪怕內(nèi)存不足時(shí),系統(tǒng)會(huì)直接拋出異常OutOfMemoryError民效,也不會(huì)去回收 進(jìn)程終止
SoftReference (軟引用) 當(dāng)內(nèi)存足夠時(shí)不會(huì)回收這種引用類型的對(duì)象憔维,只有當(dāng)內(nèi)存不夠用時(shí)才會(huì)回收 內(nèi)存不足涛救,進(jìn)行GC的時(shí)候
WeakReference (弱引用) GC一運(yùn)行就會(huì)把給回收了 GC后終止
PhantomReference (虛引用) 如果一個(gè)對(duì)象與虛引用關(guān)聯(lián),則跟沒有引用與之關(guān)聯(lián)一樣业扒,在任何時(shí)候都可能被垃圾回收器回收 任何時(shí)候都有可能

開發(fā)時(shí)检吆,為了防止內(nèi)存溢出,處理一些比較占用內(nèi)存并且生命周期長(zhǎng)的對(duì)象時(shí)凶赁,可以盡量使用軟引用和弱引用咧栗。

Tip:成員變量全部存儲(chǔ)在堆中(包括基本數(shù)據(jù)類型,引用及引用的對(duì)象實(shí)體)虱肄,因?yàn)樗麄儗儆陬愔掳澹悓?duì)象最終還是要被new出來的。
局部變量的基本數(shù)據(jù)類型和引用存在棧中咏窿,應(yīng)用的對(duì)象實(shí)體存儲(chǔ)在堆中斟或。因?yàn)樗鼈儗儆诜椒ó?dāng)中的變量,生命周期會(huì)隨著方法一起結(jié)束

內(nèi)存泄漏的定義

當(dāng)一個(gè)對(duì)象已經(jīng)不需要使用了集嵌,本該被回收時(shí)萝挤,而有另外一個(gè)正在使用的對(duì)象持有它的引用,從而導(dǎo)致了對(duì)象不能被GC回收根欧。

這種導(dǎo)致了本該被回收的對(duì)象不能被回收而停留在堆內(nèi)存中怜珍,就產(chǎn)生了內(nèi)存泄漏。

內(nèi)存泄漏與內(nèi)存溢出的區(qū)別
  • 內(nèi)存泄漏(Memory Leak)

進(jìn)程中某些對(duì)象已經(jīng)沒有使用的價(jià)值了凤粗,但是他們卻還可以直接或間接地被引用到GC Root導(dǎo)致無法回收酥泛。當(dāng)內(nèi)存泄漏過多的時(shí)候,再加上應(yīng)用本身占用的內(nèi)存嫌拣,日積月累最終就會(huì)導(dǎo)致內(nèi)存溢出OOM

  • 內(nèi)存溢出(OOM)

當(dāng) 應(yīng)用的heap資源超過了Dalvik虛擬機(jī)分配的內(nèi)存就會(huì)內(nèi)存溢出

內(nèi)存泄漏帶來的影響
  • 應(yīng)用卡頓

泄漏的內(nèi)存影響了GC的內(nèi)存分配柔袁,過多的內(nèi)存泄漏會(huì)影響應(yīng)用的執(zhí)行效率

  • 應(yīng)用異常(OOM)

過多的內(nèi)存泄漏,最終會(huì)導(dǎo)致 Dalvik可分配的內(nèi)存越來越少异逐,更加容易出現(xiàn)OOM

2. Android開發(fā)常見的內(nèi)存泄漏

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

錯(cuò)誤示例

當(dāng)調(diào)用getInstance時(shí)捶索,如果傳入的context是Activity的context。

只要這個(gè)單例沒有被釋放灰瞻,那么這個(gè)Activity也不會(huì)被釋放一直到進(jìn)程退出才會(huì)釋放腥例。

解決方案

能使用Application的Context就不要使用Activity的Content,Application的生命周期伴隨著整個(gè)進(jìn)程的周期

(2)非靜態(tài)內(nèi)部類創(chuàng)建靜態(tài)實(shí)例造成的內(nèi)存泄漏

錯(cuò)誤示例

解決方案

將非靜態(tài)內(nèi)部類修改為靜態(tài)內(nèi)部類酝润。(靜態(tài)內(nèi)部類不會(huì)隱式持有外部類)

(3)Handler造成的內(nèi)存泄漏

錯(cuò)誤示例

mHandler是Handler的非靜態(tài)匿名內(nèi)部類的實(shí)例燎竖,所以它持有外部類Activity的引用,我們知道消息隊(duì)列是在一個(gè)Looper線程中不斷輪詢處理消息袍祖,那么當(dāng)這個(gè)Activity退出時(shí)消息隊(duì)列中還有未處理的消息或者正在處理消息底瓣,而消息隊(duì)列中的Message持有mHandler實(shí)例的引用谢揪,mHandler又持有Activity的引用蕉陋,所以導(dǎo)致該Activity的內(nèi)存資源無法及時(shí)回收捐凭,引發(fā)內(nèi)存泄漏。

解決方案

創(chuàng)建一個(gè)靜態(tài)Handler內(nèi)部類凳鬓,然后對(duì)Handler持有的對(duì)象使用弱引用茁肠,這樣在回收時(shí)也可以回收Handler持有的對(duì)象,這樣雖然避免了Activity泄漏缩举,不過Looper線程的消息隊(duì)列中還是可能會(huì)有待處理的消息垦梆,所以我們?cè)贏ctivity的Destroy時(shí)或者Stop時(shí)應(yīng)該移除消息隊(duì)列中的消息

(4)線程造成的內(nèi)存泄漏

錯(cuò)誤示例

異步任務(wù)和Runnable都是一個(gè)匿名內(nèi)部類,因此它們對(duì)當(dāng)前Activity都有一個(gè)隱式引用仅孩。如果Activity在銷毀之前托猩,任務(wù)還未完成, 那么將導(dǎo)致Activity的內(nèi)存資源無法回收辽慕,造成內(nèi)存泄漏

解決方案

使用 靜態(tài)內(nèi)部類京腥,避免了Activity的內(nèi)存資源泄漏,當(dāng)然在Activity銷毀時(shí)候也應(yīng)該取消相應(yīng)的任務(wù)AsyncTask::cancel()溅蛉,避免任務(wù)在后臺(tái)執(zhí)行浪費(fèi)資源

(5)資源未關(guān)閉造成的內(nèi)存泄漏

錯(cuò)誤示例

對(duì)于使用了BraodcastReceiver公浪,ContentObserver,F(xiàn)ile船侧,Cursor欠气,Stream,Bitmap等資源的使用镜撩,應(yīng)該在Activity銷毀時(shí)及時(shí)關(guān)閉或者注銷预柒,否則這些資源將不會(huì)被回收,造成內(nèi)存泄漏

解決方案

在Activity銷毀時(shí)及時(shí)關(guān)閉或者注銷

(6)使用了靜態(tài)的Activity和View

錯(cuò)誤示例

解決方案

應(yīng)該及時(shí)將靜態(tài)的應(yīng)用 置為null琐鲁,而且一般不建議將View及Activity設(shè)置為靜態(tài)

(7)注冊(cè)了系統(tǒng)的服務(wù)卫旱,但onDestory未注銷

錯(cuò)誤示例

解決方案
//不需要用的時(shí)候記得移除監(jiān)聽sensorManager.unregisterListener(listener);

(8)不需要用的監(jiān)聽未移除會(huì)發(fā)生內(nèi)存泄露

錯(cuò)誤示例

解決方案

Tip:tv.setOnClickListener();//監(jiān)聽執(zhí)行完回收對(duì)象,不用考慮內(nèi)存泄漏
tv.getViewTreeObserver().addOnWindowFocusChangeListene,add監(jiān)聽围段,放到集合里面顾翼,需要考慮內(nèi)存泄漏

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市奈泪,隨后出現(xiàn)的幾起案子适贸,更是在濱河造成了極大的恐慌,老刑警劉巖涝桅,帶你破解...
    沈念sama閱讀 211,948評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拜姿,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡冯遂,警方通過查閱死者的電腦和手機(jī)蕊肥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人壁却,你說我怎么就攤上這事批狱。” “怎么了展东?”我有些...
    開封第一講書人閱讀 157,490評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵赔硫,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我盐肃,道長(zhǎng)爪膊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,521評(píng)論 1 284
  • 正文 為了忘掉前任砸王,我火速辦了婚禮推盛,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘谦铃。我一直安慰自己小槐,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評(píng)論 6 386
  • 文/花漫 我一把揭開白布荷辕。 她就那樣靜靜地躺著凿跳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪疮方。 梳的紋絲不亂的頭發(fā)上控嗜,一...
    開封第一講書人閱讀 49,842評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音骡显,去河邊找鬼疆栏。 笑死,一個(gè)胖子當(dāng)著我的面吹牛惫谤,可吹牛的內(nèi)容都是我干的壁顶。 我是一名探鬼主播,決...
    沈念sama閱讀 38,997評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼溜歪,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼若专!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蝴猪,我...
    開封第一講書人閱讀 37,741評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤调衰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后自阱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嚎莉,經(jīng)...
    沈念sama閱讀 44,203評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評(píng)論 2 327
  • 正文 我和宋清朗相戀三年沛豌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了趋箩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,673評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖叫确,靈堂內(nèi)的尸體忽然破棺而出爬早,到底是詐尸還是另有隱情,我是刑警寧澤启妹,帶...
    沈念sama閱讀 34,339評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站醉旦,受9級(jí)特大地震影響饶米,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜车胡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評(píng)論 3 313
  • 文/蒙蒙 一檬输、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧匈棘,春花似錦丧慈、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至簇搅,卻和暖如春完域,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瘩将。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工吟税, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人姿现。 一個(gè)月前我還...
    沈念sama閱讀 46,394評(píng)論 2 360
  • 正文 我出身青樓肠仪,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親备典。 傳聞我的和親對(duì)象是個(gè)殘疾皇子异旧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評(píng)論 2 349

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