JVM內存管理概要(《分佈式Java應用》中JVM章節摘要)

此爲《分佈式Java應用》一書中有關JVM內存管理和垃圾回收的章節筆記。


瞭解JVM的內存分配和回收機制,可以更加準確地判斷程序的運行狀況及進行性能的調優。


JVM內存空間

JVM將內存空間分爲方法區、堆、本地方法棧、PC寄存器及JVM方法棧。


方法區

方法區存放了加載類的信息、類中的靜態變量、類中定義爲final類型的常量,通過Class對象的getName等方法來獲取信息時,這些數據都來源於方法區。JVM方法區在JDK中對應Permanet Generation(持久代)。


堆中儲存的是對象實例和數組。開發人員可以設置堆的擴容策略。JDK1.2開始對堆採用分代管理的方式。堆內存是內存中最重要的一塊,也是最有必要進行深究的一部分。因爲Java性能的優化,主要就是針對這部分內存的。可通過-Xms和-Xmx控制JVM啓動時申請的最小和最大Heap內存。


新生代(堆)

多數情況下Java程序中新建的對象都從新生代分配內存。新生代有Eden Space和兩塊Survivor構成。不同的GC方式會以不同的方式來劃分Eden Space和Survivor Space。


舊生代(堆)

用於存放新生代中經過多次垃圾回收仍然存貨的對象。如果新建的對象時大對象或大數組對象,那也有可能在舊生代直接分配內存。


本地方法棧

用於存儲每個native方法的調用狀態,在JDK的實現中本地方法棧和JVM方法棧是同一個。


JVM方法棧

JVM虛擬機棧就是堆棧的棧,它的生命週期和線程一樣,每個方法被執行的時候會產生一個棧幀,用於存儲局部變量表、動態鏈接、操作數、方法出口等信息。方法的執行過程就是棧幀在JVM中出棧和入棧的過程。局部變量表中存放的是各種基本數據類型及引用類型(存放的是指向各個對象的內存地址),因此,它有一個特點:內存空間可以在編譯期間就確定,運行期不再改變。這個內存區域會有兩種可能的Java異常:StackOverFlowError和OutOfMemoryError。


Java垃圾回收機制

GC首先找到程序中不再被使用的對象,然後回收這些對象所佔用的內存。JDK採用根搜索算法找到這些對象。基本思想:從GC Roots的對象開始,向下搜索,如果一個對象不能到達GC Roots對象的時候,說明它已經不再被引用,即可被進行垃圾回收(事實,當一個對象不再被引用時,如果類重寫了finalize()方法,且沒有被系統調用過,那麼系統會調用一次finalize()方法,以完成最後的工作,在這期間,如果可以將對象重新與任何一個和GC Roots有引用的對象相關聯,則該對象可以“重生”,如果不可以,那麼就說明徹底可以被回收)。


通常採用收集器的方式實現GC。


跟蹤收集器

收集器採用的爲集中式的管理方式,全局記錄數據的引用狀態。基於一定條件的出發,執行時需要從根集合來掃描對象的引用關係,主要有賦值、標記-清除(Mark-Sweep)和標記-壓縮(Mark-Compact)三種實現算法。


標記-清除算法(Mark-Sweep)

最基礎的GC算法,將需要進行回收的對象做標記,之後掃描,有標記的進行回收,這樣就產生兩個步驟:標記和清除。這個算法效率不高,而且在清理完成後會產生內存碎片,這樣,如果有大對象需要連續的內存空間時,還需要進行碎片整理,所以,此算法需要改進。


複製算法(Copying)

新生代內存分爲三份,Eden區和2塊Survivor區,一般JVM會將Eden區和Survivor區的比例調爲8:1,保證有一塊Survivor區是空閒的,這樣,在垃圾回收的時候,將不需要進行回收的對象放在空閒的Survivor區,然後將Eden區和第一塊Survivor區進行完全清理。如果第二塊Survivor區的空間不足,就需要暫時借持久代的內存用。此算法適用於新生代。


標記-壓縮算法(Mark-Compact)

和標記-清除算法前半段一樣,只是在標記了不需要進行回收的對象後,將標記過的對象移動到一起,使得內存連續,這樣,只要將標記邊界以外的內存清理就行了。此算法適用於持久代。



Java垃圾回收相關方法

gc()

調用gc 方法提示JVM來回收未用對象,以便能夠快速地重用這些對象當前佔用的內存。當控制權從方法調用中返回時,虛擬機已經盡最大努力從所有丟棄的對象中回收了空間,調用System.gc() 等效於調用Runtime.getRuntime().gc()。


finalize()的調用及重寫

gc 只能清除在堆上分配的內存(純java語言的所有對象都在堆上使用new分配內存),而不能清除棧上分配的內存(當使用JNI技術時,可能會在棧上分配內存,例如java調用c程序,而該c程序使用malloc分配內存時)。因此,如果某些對象被分配了棧上的內存區域,對棧上的對象進行內存回收就要靠finalize()。





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