內存管理和垃圾回收是JVM很是關鍵的點,對Java性能的剖析而言,瞭解內存管理和垃圾回收的基本策略很是重要。本篇對Sun JVM 6.0的內存管理和垃圾回收作大概的描述。 1.內存管理 在程序運行過程中,會建立大量的對象,這些對象,大部分是短週期的對象,小部分是長週期的對象,對於短週期的對象,須要頻繁地進行垃圾回收以保證無用對象儘早被釋放掉,對於長週期對象,則不須要頻率垃圾回收以確保無謂地垃圾掃描檢測。爲解決這種矛盾,Sun JVM的內存管理採用分代的策略。 1)年輕代(Young Gen):年輕代主要存放新建立的對象,內存大小相對會比較小,垃圾回收會比較頻繁。年輕代分紅1個Eden Space和2個Suvivor Space(命名爲A和B) 當對象在堆建立時,將進入年輕代的Eden Space。 垃圾回收器進行垃圾回收時,掃描Eden Space和A Suvivor Space,若是對象仍然存活,則複製到B Suvivor Space,若是B Suvivor Space已經滿,則複製 Old Gen 掃描A Suvivor Space時,若是對象已經通過了幾回的掃描仍然存活,JVM認爲其爲一個Old對象,則將其移到Old Gen。 掃描完畢後,JVM將Eden Space和A Suvivor Space清空,而後交換A和B的角色(即下次垃圾回收時會掃描Eden Space和BSuvivor Space。 咱們能夠看到:Young Gen垃圾回收時,採用將存活對象複製到到空的Suvivor Space的方式來確保不存在內存碎片,採用空間換時間的方式來加速內存垃圾回收。 2)年老代(Tenured Gen):年老代主要存放JVM認爲比較old的對象(通過幾回的Young Gen的垃圾回收後仍然存在),內存大小相對會比較大,垃圾回收也相對沒有那麼頻繁(譬如可能幾個小時一次)。年老代主要採用壓縮的方式來避免內存碎片(將存活對象移動到內存片的一邊),固然,有些垃圾回收器(譬如CMS垃圾回收器)出於效率的緣由,可能會不進行壓縮。 3)持久代(Perm Gen):持久代主要存放類定義、字節碼和常量等不多會變動的信息,關於這塊的垃圾回收策略能夠參考個人另外一篇BLOG《Tomcat Context reloadabled 與 OutOfMemory(PermSpace) 》。 Class data sharing (CDS)( http://java.sun.com/j2se/1.5.0/docs/guide/vm/class-data-sharing.html)是JDK5新引入的特性,採用在虛擬機之間共享一些class定義信息(bootstrapClassLoader加載的類)的方式提速JVM的啓動和內存的佔用,主要用於客戶端,若是須要對類進行instrutment,最好把CDS關閉。(默認狀況下,JVM的server模式會關閉CDS,client模式會開啓CDS) -Xshare:off Disable class data sharing. -Xshare:on Require class data sharing to be enabled. If it could not be enabled for various reasons, print an error message and exit. -Xshare:auto The default; enable class data sharing whenever possible. 咱們經過JConsole截圖看看上面這幾個區的顯示(下圖),從左到右分別是EdenSpace、A Suvivor Space、Tenured Gen、Code Cache、Perm Gen(shared-wr)、Perm Gen(shared-ro)、Perm Gen 2.垃圾回收策略 評估垃圾回收策略的兩個重要度量是: 吞吐量(Throughput ):JVM花費在垃圾回收上的時間越長,則吞吐量越低 暫停時間(Pause time):JVM垃圾回收過程中有一個暫停期,在暫停期間,應用程序不能運行,暫停時間是暫停期的長度 很是遺憾的是,通常這兩個指標是相互衝突的,改善其中一個會影響到另一個,根據情景的不一樣咱們決定是優先考慮吞吐量仍是暫停時間,對於須要實時響應的應用,咱們須要優先考慮暫停時間,對於後臺運行應用,咱們須要優先考慮吞吐量。 在考察各類垃圾回收器以前,咱們須要瞭解一下幾個重要的策略 並行(Parallel):並行表示使用多個線程同時進行垃圾回收的工做,此策略通常會從同時改善暫停時間和吞吐量,在有多CPU內核的服務器上,這是基本上咱們要使用的策略。 併發(Concurrent):並行表示垃圾回收器的一些工做(譬如垃圾標記)與應用程序同時進行,這將更進一步縮短暫停時間,須要注意的是,同時垃圾回收器的複雜性會大大增大,基本上是會下降吞吐量, 內存碎片處理:有不壓縮、壓縮和拷貝三種策略,從空間上講,拷貝將花費更多的內存(譬如如上內存管理的Young Gen,須要維持一個額外的Suvivor空間),從時間上來說,不壓縮會減低建立對象時的內存分配效率,在垃圾回收上,拷貝策略會比壓縮策略更高效。 Sun JVM有4垃圾回收器: Serial Collector:序列垃圾回收器,垃圾回收器對Young Gen和Tenured Gen都是使用單線的垃圾回收方式,對Young Gen,會使用拷貝策略避免內存碎片,對Old Gen,會使用壓縮策略避免內存碎片。基本上,在對內核的服務器上應該避免使用這種方式。在JVM啓動參數中使用-XX:+UseSerialGC啓用Serial Collector。 Parallel Collector:併發垃圾回收器,垃圾回收器對Young Gen和Tenured Gen都是使用多線程並行垃圾回收的方式,對Young Gen,會使用拷貝策略避免內存碎片,對Old Gen,會使用壓縮策略避免內存碎片。在JVM啓動參數中使用-XX:+UseParallelGC啓用Parallel Collector。 Parallel Compacting Collector:並行壓縮垃圾回收器,與Parallel Collector垃圾回收相似,但對Tenured Gen會使用一種更有效的垃圾回收策略,此垃圾回收器在暫停時間上會更短。在JVM啓動參數中使用-XX:+UseParallelOldGC啓用Parallel Compacting Collector。 Concurrent Mark-Sweep (CMS) Collector:併發標誌清除垃圾回收器,對Young Gen會使用與Parallel Collector一樣的垃圾回收策略,對Tenured Gen,垃圾回收的垃圾標誌線程與應用線程同時進行,而垃圾清除則須要暫停應用線程,但暫停時間會大大縮減,須要注意的是,因爲垃圾回收過程更加複雜,會下降整體的吞吐量。