Android內(nèi)存管理及內(nèi)存泄露

Java 內(nèi)存分配策略

Java 程序運(yùn)行時(shí)的內(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)存在程序編譯時(shí)就已經(jīng)分配好,并且在程序整個(gè)運(yùn)行期間都存在霹肝。
  • 棧區(qū) :當(dāng)方法被執(zhí)行時(shí)估蹄,方法體內(nèi)的局部變量(其中包括基礎(chǔ)數(shù)據(jù)類型、對象的引用)都在棧上創(chuàng)建沫换,并在方法執(zhí)行結(jié)束時(shí)這些局部變量所持有的內(nèi)存將會自動(dòng)被釋放臭蚁。因?yàn)闂?nèi)存分配運(yùn)算內(nèi)置于處理器的指令集中,效率很高,但是分配的內(nèi)存容量有限垮兑。
  • 堆區(qū) : 又稱動(dòng)態(tài)內(nèi)存分配冷尉,通常就是指在程序運(yùn)行時(shí)直接 new 出來的內(nèi)存,也就是對象的實(shí)例系枪。這部分內(nèi)存在不使用時(shí)將會由 Java 垃圾回收器來負(fù)責(zé)回收雀哨。

Java是如何管理內(nèi)存

Java的內(nèi)存管理就是對象的分配和釋放問題。在 Java 中嗤无,程序員需要通過關(guān)鍵字 new 為每個(gè)對象申請內(nèi)存空間 (基本類型除外)震束,所有的對象都在堆 (Heap)中分配空間。另外当犯,對象的釋放是由 GC 決定和執(zhí)行的垢村。在 Java 中,內(nèi)存的分配是由程序完成的嚎卫,而內(nèi)存的釋放是由 GC 完成的嘉栓,這種收支兩條線的方法確實(shí)簡化了程序員的工作。但同時(shí)拓诸,它也加重了JVM的工作侵佃。這也是 Java 程序運(yùn)行速度較慢的原因之一。因?yàn)榈熘В珿C 為了能夠正確釋放對象馋辈,GC 必須監(jiān)控每一個(gè)對象的運(yùn)行狀態(tài),包括對象的申請倍谜、引用迈螟、被引用、賦值等尔崔,GC 都需要進(jìn)行監(jiān)控答毫。

監(jiān)視對象狀態(tài)是為了更加準(zhǔn)確地、及時(shí)地釋放對象季春,而釋放對象的根本原則就是該對象不再被引用洗搂。

為了更好理解 GC 的工作原理,我們可以將對象考慮為有向圖的頂點(diǎn)载弄,將引用關(guān)系考慮為圖的有向邊耘拇,有向邊從引用者指向被引對象。另外宇攻,每個(gè)線程對象可以作為一個(gè)圖的起始頂點(diǎn)驼鞭,例如大多程序從 main 進(jìn)程開始執(zhí)行,那么該圖就是以 main 進(jìn)程頂點(diǎn)開始的一棵根樹尺碰。在這個(gè)有向圖中挣棕,根頂點(diǎn)可達(dá)的對象都是有效對象译隘,GC將不回收這些對象。如果某個(gè)對象 (連通子圖)與這個(gè)根頂點(diǎn)不可達(dá)(注意洛心,該圖為有向圖)固耘,那么我們認(rèn)為這個(gè)(這些)對象不再被引用,可以被 GC 回收词身。

哪些是JVM的GC Roots

  • Class 由System Class Loader/Boot Class Loader加載的類對象厅目,這些對象不會被回收。需要注意的是其它的Class Loader實(shí)例加載的類對象不一定是GC root法严,除非這個(gè)類對象恰好是其它形式的GC root损敷;
    • 如單例模式的java類;
    • 非靜態(tài)內(nèi)部類/匿名類將持有Context深啤;
  • Thread 線程拗馒,激活狀態(tài)的線程;
    • Runnable/AsyncTask
    • TimerTask
  • Stack Local 棧中的對象溯街。每個(gè)線程都會分配一個(gè)棧诱桂,棧中的局部變量或者參數(shù)都是GC root,因?yàn)樗鼈兊囊秒S時(shí)可能被用到呈昔;
  • JNI Local JNI中的局部變量和參數(shù)引用的對象挥等;可能在JNI中定義的,也可能在虛擬機(jī)中定義
  • JNI Global JNI中的全局變量引用的對象堤尾;同上
  • Monitor Used 用于保證同步的對象肝劲,例如wait(),notify()中使用的對象郭宝、鎖等辞槐。
  • Held by JVM JVM持有的對象。JVM為了特殊用途保留的對象剩蟀,它與JVM的具體實(shí)現(xiàn)有關(guān)。比如有System Class Loader, 一些Exceptions對象切威,和一些其它的Class Loader育特。對于這些類,JVM也沒有過多的信息先朦。

可能導(dǎo)致的內(nèi)存泄露

參考 Android開發(fā)編碼規(guī)范導(dǎo)致的內(nèi)存泄露問題

  • 非靜態(tài)內(nèi)部類持有外部類的引用
  • 單例持有了 context
  • 非靜態(tài)匿名類持有外部類的引用
  • handler 內(nèi)存泄露

對以上幾點(diǎn)做一個(gè)總結(jié)

  • 不要讓生命周期長于Activity的對象持有到Activity的引用
  • 盡量使用Application的Context而不是Activity的Context
  • 盡量不要在Activity中使用非靜態(tài)內(nèi)部類缰冤,因?yàn)榉庆o態(tài)內(nèi)部類會隱式持有外部類實(shí)例的引用。使用靜態(tài)內(nèi)部類喳魏,將外部實(shí)例引用作為弱引用持有 android handler 弱引用棉浸。
  • 垃圾回收不能解決內(nèi)存泄露,了解Android中垃圾回收機(jī)制

防止Android內(nèi)存泄露的總結(jié)

  • 對 Activity 等組件的引用應(yīng)該控制在 Activity 的生命周期之內(nèi)刺彩; 如果不能就考慮使用 getApplicationContext 或者 getApplication迷郑,以避免 Activity 被外部長生命周期的對象引用而泄露枝恋。
  • 盡量不要在靜態(tài)變量或者靜態(tài)內(nèi)部類中使用非靜態(tài)外部成員變量(包括context ),即使要使用嗡害,也要考慮適時(shí)把外部成員變量置空焚碌;也可以在內(nèi)部類中使用弱引用來引用外部類的變量。
  • 對于生命周期比Activity長的內(nèi)部類對象霸妹,并且內(nèi)部類中使用了外部類的成員變量十电,可以這樣做避免內(nèi)存泄漏:
  • 將內(nèi)部類改為靜態(tài)內(nèi)部類靜態(tài)內(nèi)部類中使用弱引用來引用外部類的成員變量
  • Handler 的持有的引用對象最好使用弱引用,資源釋放時(shí)也可以清空 Handler 里面的消息叹螟。比如在 Activity onStop 或者 onDestroy 的時(shí)候鹃骂,取消掉該 Handler 對象的 Message和 Runnable.
  • 在 Java 的實(shí)現(xiàn)過程中,也要考慮其對象釋放罢绽,最好的方法是在不使用某對象時(shí)畏线,顯式地將此對象賦值為 null,比如使用完Bitmap 后先調(diào)用 recycle()有缆,再賦為null,清空對圖片等資源有直接引用或者間接引用的數(shù)組(使用 array.clear() ; array = null)等象踊,最好遵循誰創(chuàng)建誰釋放的原則。
  • 正確關(guān)閉資源棚壁,對于使用了BraodcastReceiver杯矩,ContentObserver,F(xiàn)ile袖外,游標(biāo) Cursor史隆,Stream,Bitmap等資源的使用曼验,應(yīng)該在Activity銷毀時(shí)及時(shí)關(guān)閉或者注銷泌射。
  • 保持對對象生命周期的敏感,特別注意單例鬓照、靜態(tài)對象熔酷、全局性集合等的生命周期。

參考

GC的兩種判定方法:引用計(jì)數(shù)與引用鏈
Android開發(fā)編碼規(guī)范導(dǎo)致的內(nèi)存泄露問題
android handler 弱引用
Android開發(fā)從GC root分析內(nèi)存泄漏

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末豺裆,一起剝皮案震驚了整個(gè)濱河市拒秘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌臭猜,老刑警劉巖躺酒,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蔑歌,居然都是意外死亡羹应,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進(jìn)店門次屠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來园匹,“玉大人雳刺,你說我怎么就攤上這事≠怂啵” “怎么了煞烫?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長累颂。 經(jīng)常有香客問我滞详,道長,這世上最難降的妖魔是什么紊馏? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任料饥,我火速辦了婚禮,結(jié)果婚禮上朱监,老公的妹妹穿的比我還像新娘岸啡。我一直安慰自己,他們只是感情好赫编,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布巡蘸。 她就那樣靜靜地躺著,像睡著了一般擂送。 火紅的嫁衣襯著肌膚如雪悦荒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天嘹吨,我揣著相機(jī)與錄音搬味,去河邊找鬼。 笑死蟀拷,一個(gè)胖子當(dāng)著我的面吹牛碰纬,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播问芬,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼悦析,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了此衅?” 一聲冷哼從身側(cè)響起强戴,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎炕柔,沒想到半個(gè)月后酌泰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體媒佣,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡匕累,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了默伍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片欢嘿。...
    茶點(diǎn)故事閱讀 39,834評論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡衰琐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出炼蹦,到底是詐尸還是另有隱情羡宙,我是刑警寧澤质涛,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布抱完,位于F島的核電站,受9級特大地震影響阐滩,放射性物質(zhì)發(fā)生泄漏虑省。R本人自食惡果不足惜匿刮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望探颈。 院中可真熱鬧熟丸,春花似錦、人聲如沸伪节。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽怀大。三九已至纱兑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間叉寂,已是汗流浹背萍启。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留屏鳍,地道東北人勘纯。 一個(gè)月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像钓瞭,于是被迫代替她去往敵國和親驳遵。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評論 2 354

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