Android常見內(nèi)存泄露北苟,學會這六招大大優(yōu)化APP性能

?很多開發(fā)者都知道,在面試的時候會經(jīng)常被問到內(nèi)存泄露和內(nèi)存溢出的問題刺桃。

內(nèi)存溢出(Out Of Memory粹淋,簡稱 OOM)吸祟,通俗理解就是內(nèi)存不夠瑟慈,即內(nèi)存占用超出內(nèi)存的空間大小桃移。

內(nèi)存泄漏(Memory Leak),簡單理解就是內(nèi)存使用完畢之后本該垃圾回收卻未被回收葛碧。

在正式了解內(nèi)存泄露之前借杰,首先來簡單回顧一下 Java 內(nèi)存分配策略。

Java 程序運行時的內(nèi)存分配策略有三種,分別是靜態(tài)分配进泼、棧式分配蔗衡、堆式分配,對應(yīng)的主要內(nèi)存空間分別是靜態(tài)存儲區(qū)(也稱方法區(qū))乳绕、棧區(qū)绞惦、堆區(qū)。

靜態(tài)存儲區(qū)(方法區(qū))

主要存放靜態(tài)數(shù)據(jù)洋措、全局 static 數(shù)據(jù)和常量济蝉。這塊內(nèi)存在程序編譯時就已經(jīng)分配好,并且在程序整個運行期間都存在菠发。

棧區(qū)

當方法被執(zhí)行時王滤,方法體內(nèi)的局部變量都在棧上創(chuàng)建,并在方法執(zhí)行結(jié)束時這些局部變量所持有的內(nèi)存將會自動被釋放滓鸠。因為棧內(nèi)存分配運算內(nèi)置于處理器的指令集中雁乡,效率很高,但是分配的內(nèi)存容量有限糜俗。

堆區(qū)

又稱動態(tài)內(nèi)存分配踱稍,通常就是指在程序運行時直接 new 出來的內(nèi)存。這部分內(nèi)存在不使用時將會由 Java 垃圾回收器來負責回收悠抹。

在 Java 中寞射,內(nèi)存的分配是由程序完成的,而內(nèi)存的釋放是由 GC 完成的锌钮,這種方式大大簡化了程序員的工作桥温,但同時卻加重了 JVM 的工作,這也是 Java 程序運行速度較慢的原因之一梁丘。GC 為了能夠正確釋放對象侵浸,必須監(jiān)控每一個對象的運行狀態(tài),包括對象的申請氛谜、引用掏觉、被引用、賦值等值漫,監(jiān)視對象的狀態(tài)是為了更加準確地澳腹、及時地釋放對象,而釋放對象的根本原則就是該對象不再被引用。

Java 有了垃圾回收功能酱塔,程序員無需手動管理內(nèi)存分配沥邻,減少了段錯誤導致的閃退,也減少了內(nèi)存泄漏導致的堆空間膨脹羊娃,讓編寫的代碼更加安全唐全。但是 Java 中依然有可能發(fā)生內(nèi)存泄露,而 Android 主要使用 Java 作為開發(fā)語言蕊玷,在開發(fā)過程中很可能一個很小的錯誤都會引起內(nèi)存的泄露邮利。有內(nèi)存泄露存在時,APP 就會浪費大量的內(nèi)存垃帅,就會由于內(nèi)存不夠而頻繁進行垃圾回收延届,大家知道垃圾回收是非常耗時的操作,這樣就會導致 APP 的嚴重卡頓贸诚。在最壞的時候方庭,甚至由于內(nèi)存耗盡導致OutOfMemery,最終程序異常退出赦颇。

內(nèi)存泄露是一個令很多開發(fā)者頭疼的問題二鳄,那么我們今天就來學習一下 Activity 有關(guān)的內(nèi)存泄露問題。

在 Android 中媒怯,泄露 Context 對象的問題尤其嚴重订讼,特別像 Activity 這樣的 Context 對象會引用大量很占用內(nèi)存的對象,如果 Context 對象發(fā)生了內(nèi)存泄漏扇苞,那它所引用的所有對象都被泄漏了欺殿。Activity 是非常重量級的對象,所以我們應(yīng)該極力避免妨礙系統(tǒng)對其進行回收鳖敷,然而實際情況是有多種方式會無意間就泄露了Activity 對象脖苏。

1. 靜態(tài)變量造成的內(nèi)存泄漏

最簡單的泄漏 Activity 就是在 Activity 類中定義一個 static 變量,并將其指向一個運行中的 Activity 實例定踱。如果在 Activity 的生命周期結(jié)束之前棍潘,沒有清除這個引用,那它就會泄漏崖媚。由于 Activity 的類對象是靜態(tài)的亦歉,一旦加載,就會在 APP 運行時一直常駐內(nèi)存畅哑,如果類對象不卸載肴楷,其靜態(tài)成員就不會被垃圾回收。

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

另一種類似的情況是對經(jīng)常啟動的 Activity 實現(xiàn)一個單例模式荠呐,讓其常駐內(nèi)存可以使它能夠快速恢復(fù)狀態(tài)赛蔫。

如我們有一個創(chuàng)建起來非常耗時的 View砂客,在同一個 Activity 不同的生命周期中都保持不變呢,就為它實現(xiàn)一個單例模式呵恢。一旦 View 被加載到界面中鞠值,它就會持有 Context 的強引用,也就是我們的 Activity 對象瑰剃。

由于我們是通過一個靜態(tài)成員引用了這個 View齿诉,所以我們也就引用了 Activity筝野,因此 Activity 就發(fā)生了泄漏晌姚。所以一定不要把加載的 View 賦值給靜態(tài)變量,如果你真的需要歇竟,那一定要確保在 Activity 銷毀之前將其從 View 層級中移除挥唠。

3. 內(nèi)部類造成的內(nèi)存泄漏

我們經(jīng)常在 Activity 內(nèi)部定義一個內(nèi)部類,這樣做可以增加封裝性和可讀性焕议。但是如果當我們創(chuàng)建了一個內(nèi)部類的對象宝磨,并通過靜態(tài)變量持有了 Activity 的引用,那也會可能發(fā)生 Activity 泄漏盅安。

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

在 Activity 內(nèi)定義了一個匿名的 AsyncTask 對象唤锉,就有可能發(fā)生內(nèi)存泄漏。如果 Activity 被銷毀之后 AsyncTask 仍然在執(zhí)行别瞭,那就會阻止垃圾回收器回收Activity 對象窿祥,進而導致內(nèi)存泄漏,直到執(zhí)行結(jié)束才能回收 Activity蝙寨。

同樣的晒衩,使用 Thread 和 TimerTask 也可能導致 Activity 泄漏。只要它們是通過匿名類創(chuàng)建的墙歪,盡管它們在單獨的線程被執(zhí)行听系,它們也會持有對 Activity 的強引用,進而導致內(nèi)存泄漏虹菲。

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

定義一個匿名的 Runnable 對象并將其提交到 Handler 上也可能導致 Activity 泄漏靠胜。Runnable 對象間接地引用了定義它的 Activity 對象,而它會被提交到Handler 的 MessageQueue 中毕源,如果它在 Activity 銷毀時還沒有被處理浪漠,就會導致 Activity 泄漏。

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

如系統(tǒng)服務(wù)可以通過 context.getSystemService 獲取脑豹,它們負責執(zhí)行某些后臺任務(wù)郑藏,或者為硬件訪問提供接口。如果 Context 對象想要在服務(wù)內(nèi)部的事件發(fā)生時被通知瘩欺,那就需要把自己注冊到服務(wù)的監(jiān)聽器中必盖。然而拌牲,這會讓服務(wù)持有 Activity 的引用,如果開發(fā)者忘記在 Activity 銷毀時取消注冊歌粥,也會導致 Activity泄漏塌忽。

這里只是簡單的分析了常見的有關(guān) Activity 導致的內(nèi)存泄露,其實導致內(nèi)存泄露的地方還有很多失驶,但是基本原理都一樣土居。由于篇幅原因,這里不做過多介紹嬉探,以后再逐漸進行分析和學習擦耀。

雖然現(xiàn)在手機內(nèi)存越來越大,內(nèi)存泄露不會像以前由于內(nèi)存過小造成 OOM涩堤。但是過量的內(nèi)存泄露依然會造成內(nèi)存溢出眷蜓,影響用戶體驗,所以解決好內(nèi)存泄露的問題非常重要胎围。

今天就先分享到這里吁系,后續(xù)將推出更多精彩內(nèi)容,歡迎一起探討學習進步白魂。

此文章為分享達人秀(ShareExpert)——鑫鱻原創(chuàng)汽纤,若轉(zhuǎn)載請備注出處,特此聲明福荸!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蕴坪,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子逞姿,更是在濱河造成了極大的恐慌辞嗡,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,378評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件滞造,死亡現(xiàn)場離奇詭異续室,居然都是意外死亡,警方通過查閱死者的電腦和手機谒养,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評論 3 399
  • 文/潘曉璐 我一進店門挺狰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人买窟,你說我怎么就攤上這事丰泊。” “怎么了始绍?”我有些...
    開封第一講書人閱讀 168,983評論 0 362
  • 文/不壞的土叔 我叫張陵瞳购,是天一觀的道長。 經(jīng)常有香客問我亏推,道長学赛,這世上最難降的妖魔是什么年堆? 我笑而不...
    開封第一講書人閱讀 59,938評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮盏浇,結(jié)果婚禮上变丧,老公的妹妹穿的比我還像新娘。我一直安慰自己绢掰,他們只是感情好痒蓬,可當我...
    茶點故事閱讀 68,955評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著滴劲,像睡著了一般攻晒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上哑芹,一...
    開封第一講書人閱讀 52,549評論 1 312
  • 那天炎辨,我揣著相機與錄音捕透,去河邊找鬼聪姿。 笑死,一個胖子當著我的面吹牛乙嘀,可吹牛的內(nèi)容都是我干的末购。 我是一名探鬼主播,決...
    沈念sama閱讀 41,063評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼虎谢,長吁一口氣:“原來是場噩夢啊……” “哼盟榴!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起婴噩,我...
    開封第一講書人閱讀 39,991評論 0 277
  • 序言:老撾萬榮一對情侶失蹤擎场,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后几莽,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體迅办,經(jīng)...
    沈念sama閱讀 46,522評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,604評論 3 342
  • 正文 我和宋清朗相戀三年章蚣,在試婚紗的時候發(fā)現(xiàn)自己被綠了站欺。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,742評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡纤垂,死狀恐怖矾策,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情峭沦,我是刑警寧澤贾虽,帶...
    沈念sama閱讀 36,413評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站吼鱼,受9級特大地震影響蓬豁,放射性物質(zhì)發(fā)生泄漏履磨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,094評論 3 335
  • 文/蒙蒙 一庆尘、第九天 我趴在偏房一處隱蔽的房頂上張望剃诅。 院中可真熱鬧,春花似錦驶忌、人聲如沸矛辕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽聊品。三九已至,卻和暖如春几苍,著一層夾襖步出監(jiān)牢的瞬間翻屈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評論 1 274
  • 我被黑心中介騙來泰國打工妻坝, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留伸眶,地道東北人。 一個月前我還...
    沈念sama閱讀 49,159評論 3 378
  • 正文 我出身青樓刽宪,卻偏偏與公主長得像厘贼,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子圣拄,可洞房花燭夜當晚...
    茶點故事閱讀 45,747評論 2 361

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