2011-03-18 57 views
15

(請注意,當我說「JVM」,我真的是「熱點」,和我運行最新的Java 1.6的更新。)鼓勵JVM進行GC而不是增加堆?

示例情況:

我的JVM與-Xmx集運行到1GB。目前,這個堆已經分配了500MB,其中使用了450MB。該程序需要在堆上加載另一個200 MB。目前,堆中有300mb的「可收集」垃圾(我們假設它全部是最老的一代)。

在正常操作下,JVM會將堆增長到700 MB左右,並且垃圾收集當它接近它時。

我想在這種情況下,JVM首先要gc,然後分配新的東西,這樣我們最終將堆大小保持在500mb,堆已用到350mb。

是否有一個JVM的參數組合,做了嗎?

回答

2

在分配額外的200MB對象之前,您通常可以調用System.gc()方法,但這只是JVM的一個暗示,它可以或不可以遵循,並且在任何情況下您都不會知道何時發生這種情況。如文件中所述,這是一項盡力而爲的要求。

順便說考慮到垃圾收集是一個繁重的操作,所以如果沒有特殊需要做到這一點,就不要試圖強迫它。

只是要知道:如果你設置了-Xmx1G那麼你告訴JVM 1GB是堆的最大空間,既然你指定了那個,我不明白爲什麼它應該儘量保持它低它知道1GB將仍然可以(我們處於內存管理語言的背景下)。如果你不想堆,以增加多隻減少最大值,所以它會被強制分配新對象之前做GC,否則你爲什麼要告訴它使用1GB的?

+1

在我看來,沒有必要釋放未使用的內存的概念是當今「現代」編程語言的主要問題。我分享Electrons_Ahoy的關切。不幸的是,電腦不再像以前那樣變得更快。我們必須編寫更好的軟件! – Seba 2011-03-18 18:05:27

+0

如果你想忘記內存分配,這是一個折衷,沒有什麼可以阻止你使用C或C++並管理任何你想要的東西。但是,如果你選擇一個照顧自己以最佳方式行事的環境,那麼你就不應該試圖強迫自己的行爲。由於我們是在Java環境下,所以你的論證基本上沒有用處,也沒有人強迫你使用它:)這就像爭吵與某個擁有大污染汽車的人一樣,只是把你的自行車忘掉污染。 – Jack 2011-03-18 18:08:18

+0

這可能是有用的,因爲當使用的堆更小時,完整的gc會更便宜。如果您可以在「fullGC now-> recover 500M->添加500M新對象」和「添加500M->觸發自動GC->恢復500M」之間進行選擇,那麼首先會更便宜。另外,儘管文檔明確聲明System.gc()將被視爲「一個建議」,但它確實起作用,就好像它被強制寫入我的有限混亂中一樣。這並不是一個好主意 - 一個1G的堆一個fullgc會導致一個明顯的掛起 - 至少幾秒鐘完全鎖定。 – 2011-03-18 18:10:16

10

你可以嘗試指定-XX:MinHeapFreeRatio-XX:MaxHeapFreeRatio控制堆擴展和收縮:

  • -XX:MinHeapFreeRatio - 當自由空間在一代的百分比低於此值生成進行擴展以滿足這一比例。默認值是40
  • -XX:MaxHeapFreeRatio - 當自由空間在一代的百分比超過此值會產生收縮,以滿足該值。默認爲70.

您可能還想通過指定-XX:+UseConcMarkSweepGC來試驗併發GC。根據您的應用程序,它可以保持堆大小更低的CPU額外週期的代價。

的JVM否則將使用內存指定爲可用時,它的最佳做到這樣。你可以指定一個較低的數額一樣-Xmx768m保持它包含的,它可能運行正常,雖然你會增加你在重負載情況下運行內存不足的風險。真正的整體使用較少的內存的唯一方法是編寫使用較少的內存:)

+0

-1這些選項僅適用於**串行**垃圾回收器(即無人使用的回收器)。另外,'CMS'一般不如'G1',儘管你的答案可能早於它。 – 2015-01-30 09:41:04

+0

@AleksandrDubinsky雖然'G1'是一個非常好的收集器,但在Java 7中,它完全不適合任何對延遲敏感的系統,因爲它不會收集permgen,所以它可以執行很多類加載和卸載。 Java 8沒有這個問題 – Leliel 2016-01-20 22:13:41

+0

@Leliel我不認爲任何收集器都會收集Java 7上的permgen。因此名稱爲「永久生成」。 – 2016-02-04 11:38:58

8

有四個(實際上是5個)不同垃圾收集器在HotSpot中,並且你的選項對於每一個都是不同的。

  • 串行收集器有-XX:MinHeapFreeRatio-XX:MaxHeapFreeRatio,它可以讓你或多或少地直接控制行爲。然而,我對串行收集器沒有多少經驗。
  • 並行收集器(-XX:+UseParallelOldGC)具有-XX:MaxGCPauseMillis=<millis>-XX:GCTimeRatio=<N>。設置較低的最大暫停時間通常會導致收集器使堆積變小。但是,如果暫停時間已經很短,那麼堆不會變小。 OTOH,如果最大暫停時間設置得太低,應用程序可能會花費所有時間進行收集。設置較低的gc時間比率通常也會使堆積變小。您告訴gc,您願意將更多的CPU時間用於收集,以換取更小的堆。但是,這只是一個提示,可能沒有任何作用。在我看來,爲了儘量減少堆的大小,平行收集器已經接近無法使用了。如果讓它運行一段時間並且應用程序的行爲保持不變,此收集器的工作效果會更好(它會自行調整)。
  • CMS收集器(-XX:+UseConcMarkSweepGC)通常需要更大的堆來實現低暫停時間的主要目標,所以我不會討論它。
  • 新的G1收藏家(-XX:+UseG1GC)不像老收藏家那樣死腦筋。我發現它自己選擇一個較小的堆大小。它有很多調整選項,儘管我只是開始研究它們。 -XX:InitiatingHeapOccupancyPercent,-XX:G1HeapWastePercent,-XX:G1ReservePercent-XX:G1MaxNewSizePercent可能是感興趣的。

看看official documentation爲垃圾收集器以及this list of flags