Java內存管理-- GC(Garbage Collection)的基本概念 --Hotspot的分代回收

引用:http://www.daniel-journey.com/

可能會對原文加上個別註釋,用紅色 標識出來

==================================================

這是Java內存管理系列文章 的 第一篇。

GC的概念

GC是一種自動內存管理程序,與之相對應的是C++採用的內存管理方式。GC主要的職責就是分配內存;保證被引用的對象始終在內存中;把不被應用的 對象從內存中釋放。被引用的對象稱之爲Live 對象;不被引用的對象就是Dead對象,是需要回收的。(引出概念弱引用,weak reference )任何事物都有光面和黑暗兩面,原因很簡單GC是一個很複雜的東西:-)。

GC會自動計算對象被引用的情況,只要對象不在被引用,相應的內存就會被回收,而C++中需要開發人員通過代碼來“顯示”地回收內存,如果程序員沒 有回收就會導致內存的泄露(內存泄露的原因有很多種這只是其中一個)。C++中還有經常出現的一個問題是一個對象在還有其他引用存在的情況下,就被程序給 回收了,導致其他引用訪問該對象時出現嚴重錯誤。另外,GC非常重要的一點就避免內存碎片,道理跟windows的磁盤整理一樣,把使用中各個內存塊整合 起來,這樣才能保證有足夠的空間來存儲大對象。

理想的GC

一個理想的GC要能夠滿足以下幾點:

  • 該回收的回收,不改回收的絕不回收
  • GC要快而且GC運行的時候不能導致應用程序的停頓。
  • 限制內存碎片,對象被回收以後,所使用的內存會被回收,如果不加處理內存中就會出現大量的內存碎片,這樣就有可能導致因爲沒有足夠的連續空間分配 給某些大對象而導致OutofMemory。消除內存碎片的的手段之一就是“內存壓縮”
  • 可擴展性(Scalability),內存的分配和回收都不能成爲應用程序的瓶頸。

GC的設計選擇

  • 串行回收(Serial)VS並行回收(Parallel)。 串行就是不管有多少個CPU,始終只有一個 CPU用來執行回收操作,而並行就是把整個回收工作拆分成多個,由多個CPU同時執行。並行回收執行會快,但複雜度增加,另外也有其他一些副作用,比如內 存碎片會增加。
  • 併發執行(Concurrent)VS應用程序停止(Stop-the-world)。 Stop-the- world的GC方式在執行GC的同時會導致應用程序的暫停。併發執行的GC雖然不會導致應用程序的暫停,但由於併發執行GC要解決和應用程序的執行衝突 (應用程序可能會在GC的過稱中修改對象),併發執行GC執行的消耗會高於Stop-the-world,而且執行也需要更多的內存堆。
  • 壓縮(Compacting)VS不壓縮(Non-compacting)VS拷貝(Copying)。 爲了 減少內存碎片,支持壓縮的GC會把所有的活對象搬遷到一起,然後將之前佔用的內存全部回收。不壓縮式的GC顧名思義就是在GC的過程中不壓縮內存,較之壓 縮式的GC,不壓縮式的GC回收內存快了,而分配內存慢了,而且無法解決內存碎片的問題。拷貝式的GC會將活對象拷貝到不同的內存區域中,這種方式的優點 是源數據可以被認爲已經清空並可以用來分配,缺點也很明顯,需要拷貝數據和額外的內存。

GC的性能評判標準

  • 生產力(Throughput )—全部時間中不用於GC的比例。
  • GC的開銷— 全部時間中用於GC的比例。
  • 暫停時間 —GC過程中應用程序執行暫停的時間。
  • GC的頻率 —通過跟應用程序的執行比較來得到GC的執行頻率。
  • 支持GC運行所需使用的內存大小 —例如heap的大小。
  • GC的及時性(Promptness)— 一個對象從被廢棄到內存被回收之間的時間差。

這是Java內存管理系列文章 的 第二篇,上一篇是Java內存管理之基礎概 念——GC(Garbage Collection)的基本概念

如果大家讀過本系列的第一篇文章Java 內存管理之基礎概念——GC(Garbage Collection)的基本概念 就會理解到實現一個優秀的GC算法的確是一個很大的挑戰。 Hostspot虛擬機採用了“分代回收”的策略,而“分”的非常重要的一個依據就是根據對象存在的時間的長短分成若干個“代 (Gerneration)”,每個代上可以採取不同的GC策略。而採用這種“分代回收”策略是利用了2條潛規則,而且這兩條潛規則不只限於Java

  • 絕大對數的對象不會被長時間引用,這些對象在他的“青年期”就會被回收。
  • 幾乎不存在很老和很新對象之間的引用

依據這兩條潛規則,Hotspot分離出新生代 (Yound Generation)和舊生代 (Old Generation)。由於新生代的空間通常都比較小而且可能存在大量不再被引用的對象,所以針對新生代的GC執行頻率高、速度快

在新生代中存在了一定時間還沒被GC掉的對象最終會被提升到舊生代。舊生代空間比新生代的要大,但它的佔用率增長會比較緩慢 ,因此,舊生代的GC執 行頻率低,但需要更長的時間來完成。


對新生代的GC側重的是速度而且執行頻繁,與此相反舊生代的GC側重的是空間的利用率,即便在舊生代GC頻率低的情況下依然要能夠正常地工作。

另外還有一個永生代 (Permanent Generation) ,永生代中的保存的對象都是JVM用來方便管理GC的,例如類和方法對象以及它們的描述對象。(Sun的JVM不回收PermGen,由於動態語言產生類會比較多,有時就會出現PermGen Overflow。另外推薦用JRockit JVM )

新生代由一個Eden區域和2個survivor空間構成 。絕大多數對象先分配到Eden中(有一些大的對象會可能會直接分配到舊生代 中),survivor空間中的對象至少經歷過一次新生代的GC,所以這些對象在被轉移到舊生代之前都先暫且保留在survivor空間中。同一時間兩個 survivor空間中有一個用來保存對象,而另一個是空的,用來在下次的新生代GC中保存對象。


發佈了43 篇原創文章 · 獲贊 17 · 訪問量 33萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章