從Java垃圾回收機制窺探內存優化

回答一個疑問

這篇文章講的是Java的JVM的垃圾回收機制,但是Android使用的虛擬機是Dalvik或者ART,那麼下面講的垃圾回收機制是否適用於Android呢?

答案是,Yes,是可以類比的。

(增補)
文章末尾有人提出了質疑: JVM 的內存模型和 Android 虛擬機是區別的?

答案:是的,Android基於寄存器,jvm基於堆棧,本文其實避免了這樣的探討,那是因爲在邏輯上它們其實沒有太大區別,Android作爲移動操作系統基於寄存器,可以極大提高它的訪存速度,從而提高它的程序運行速度,堆棧訪存就慢些。這是最大的區別,在這裏做出說明。

其他的問題我也在評論裏做出了迴應,有任何問題都可以在下面探討,如果本文有重大漏洞,我會卸載勘誤
一欄中,大家可以關注一下。

開始

作爲Android工程師,我看過很多關於Android內存泄漏的相關優化的文章,其中大部分都是告訴你該怎麼做,做哪些,列一些具體的措施。很少解釋爲什麼要這麼做,即使解釋,也只是一筆帶過。

今天,我就以內存回收爲突破口,向大家解釋從底層到上層,是如何配合完成內存回收的。我們就從Java程序運行時的內存區域開始吧。

運行時內存區域,指的是當你的程序被JVM加載進來執行的時候,內存是怎麼分配的。

下面,就是Java程序運行時的內存模型

這裏寫圖片描述
如上圖所示,當你的Java字節碼執行起來的時候,虛擬機就會它所管理的內存大致分成這五個部分,把你的代碼,產生的對象等等分別扔到這五個框框裏:
方法區:用於存儲類信息,常量,靜態變量,編譯後的代碼等等這些
本地方法棧:用於爲本地方法的執行提供服務(可以不瞭解)
虛擬機棧:是虛擬機執行Java方法的重要內存模型。內部有一個局部變量表,這個表存儲了對象引用(這個局部變量表常被我們成爲棧)。
堆:存儲對象實例的區域(比如 A a=new A(),那麼 a這個引用就保存在上面的局部變量表中,而new A() 的這個對象就放在堆中)
程序計數器:用來記錄當前線程執行的字節碼的地址,指示執行引擎執行代碼。
執行引擎:哎呀臥槽,剛纔執行到哪一步來着?
程序計數器:傻逼。
其實上面那五個區域,和這篇文章關係最緊密的時堆和虛擬機棧中的局部變量表(也就是我們常說的棧),棧中主要保存了對象的引用,堆中保存了實際的對象,因此,實際上堆佔了整個程序運行內存的大頭,因此,內存回收就發生在堆中。

當程序運行時,然後躲在暗處的那個飢渴難耐端的垃圾回收機制(GC)就馬上跳出來了。虎視眈眈的盯着堆中的對象,專門找那些“落單”的對象….

那麼,GC是怎麼知道哪個對象“落單”了呢,答案是GC Roots引用鏈。

通過這個引用鏈往下搜索,所有在這些鏈條上的對象都拿到了免死金牌,而其餘就是落單的,它們隨後就會被GC回收。
關於GC引用鏈無論怎麼說,都很難想象,那沒關係,我來畫一畫就好了。
這裏寫圖片描述

GC程序從棧頂開始一直找到棧底,尋找每個對象引用所對應的對象實例,然後在實例中尋找是否有指向其他對象的引用,若有,繼續找(這一部分並沒有畫出,但是也是重點),沒有,則回到棧中,繼續往棧底搜索。
當然,GC不止會在棧中尋找引用,還會在靜態存儲區(存儲靜態變量的信息存儲在方法區)中尋找引用,(因爲有的堆中的對象在棧中沒有引用,它的引用在靜態存儲區,類似於 static A a =new A() )
當那些待回收的對象被標記之後,GC就會開始回收對象釋放內存。GC的回收算法有很多種,一般虛擬機配合多種內存回收算法來實現內存的高效回收,但是這些和我們其實關係不大,因此可以略過。

好了,我們終於把Java內存回收的機理講完了,那麼內存優化背後的機理也基本被我們扒開了:

不再使用對象時,將引用置空,那麼GC順着棧或者靜態存儲區中的引用就找不到堆中對應的對象,那麼這個對應的對象就會被回收。
儘量不要在生命週期較長(程序執行期間可能都不會被收回)的對象實例中引用其他的不必要的佔內存較大的對象實例
很多Android優化場景,基本圍繞了一個點:

Android中Activity,context,bitmap等佔據較大的內存空間對象,在不用的時候,一定保證當前對象的直接引用和間接引用全部被置爲空。內存才能被釋放。(重點注意多線程和網絡請求這種不可控的場景)
所以Java內存優化一個最根本的準則,就是努力使你的程序適配Java的GC機制。

後記

最近下定決心要涉足新領域,因此給自己定下目標,從這一篇開始,要系統的歸納自己所學的知識技術以及積攢的經驗,以文章的方式產出。內容主要以Java+Android相關爲主,以JS+React-native次之,然後是一些基於python的有意思的項目(是大學裏寫的,會重新整理)。

大家放心,我的文章會保證一貫的簡單友好,至少同一個層次的知識,我的文章能比別人更加友好,我有這樣的信心。

回到這篇文章本身,其實在重新整理的時候,我已經發現最近掘金上已經有人把Android優化整理了一個系列文章,我覺得寫的很不錯,在這裏也可以推薦給大家@anly_jun: android優化系列。

當然,如果你比較欣賞我的文章風格,歡迎關注我,我會在保證文章質量的前提下,提高寫作速度的。

共勉

勘誤

暫無

參考

《深入理解Java虛擬機》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章