2010-01-21 125 views
33

isnotpossible增加VM啓動後Java堆的最大大小。這是什麼技術原因?垃圾收集算法是否依賴於具有固定數量的內存來處理?還是出於安全原因,通過消耗所有可用內存來阻止Java應用程序DOS系統上的其他應用程序?爲什麼Java堆的最大大小是固定的?

+0

類似的問題:「爲什麼(星期日)JVM對內存使用一個固定的上限( -Xmx)?」 - http://stackoverflow.com/questions/3358328/why-does-the-sun-jvm-have-a-fixed-upper-limit-for-memory-usage-xmx – sleske 2012-02-28 12:24:14

回答

23

在Sun的JVM,最後我就知道,整個堆必須在連續的地址空間進行分配。我認爲,對於大堆值,在啓動後添加到地址空間非常困難,同時確保它保持連續。你可能需要在啓動時獲得它,或者根本不需要。因此,它是固定的。

即使它不是全部立即使用,爲整個堆的地址空間在啓動時保留。如果它不能爲您傳遞的-Xmx的值保留足夠大的連續地址空間塊,則它將無法啓動。這就是爲什麼在32位Windows上分配大於1.4GB的堆是很困難的 - 因爲很難找到這種大小或更大的連續地址空間,因爲某些DLL喜歡在某些地方加載,分割地址空間。因爲地址空間非常多,所以當你使用64位時,這並不是一個問題。

這幾乎肯定是出於性能的考慮。我無法找到一個很好的鏈接,詳細說明這進一步,但這裏是從彼得·凱斯勒一個相當不錯的報價(full link - 一定要閱讀註釋),我發現搜索時。我相信他在Sun的JVM上工作。

我們需要爲堆的連續存儲器 區域的原因是,我們有一個 一束被 索引由(縮放)偏移量從 開始堆的側的數據結構。例如,我們 跟蹤與 「卡片標記陣列」,其具有用於每個512個字節堆的一個字節 對象引用的更新。當我們 存儲在堆的參考,我們有 來標記 卡片標記陣列中的對應字節。我們右移商店的 目的地址和 使用該索引卡片標記陣列。 趣味算術解決遊戲中,你 不能用Java做,你去(有 在C :-)發揮++。

這是在2004年 - 我不確定自那時以來發生了什麼變化,但我確信它仍然成立。如果你使用像Process Explorer的一個工具,你可以看到,虛擬大小(添加虛擬大小和私人大小的內存列)的Java應用程序包括從啓動點的總堆大小(加上其他所需的空間,毫無疑問) ,即使在過程中「拿來主義」將是沒有在附近直到堆開始填滿記憶...

4

我認爲這個簡短而尖銳的答案是因爲Sun沒有發現開發它所花費的時間和成本。

對於這樣的功能,最引人注目的用例就是桌面上的IMO和Java,在啓動JVM的機制方面,Java一直是桌面上的災難。我懷疑那些最關心這些問題的人傾向於將重點放在服務器端,並查看最好留給本地包裝的其他細節。這是一個不幸的決定,但它應該是決定應用程序的正確平臺時的決定點之一。

+0

如果你可以成長,一個非常合理的要求也能夠縮小,而Sun JVM真的不喜歡放棄內存。 Microsoft JVM可以使用系統中的所有內存。 – 2010-01-21 15:32:03

+0

@托爾比約恩Ravn的安德森,它既可以收縮,雖然這是一個有點最近和不良記錄的能力(以及一些在桌面上真的糟糕到已丟失)。請參閱-XX:MaxHeapFreeRatio和-XX:MinHeapFreeRatio http://stackoverflow.com/questions/763295/setting-jvm-heap-size-at-runtime/763305#763305 – Yishai 2010-01-21 16:03:22

+0

未記錄的XX選項不計數:) – 2010-01-21 16:58:27

3

我的直覺是,它與內存管理相關的操作系統上運行的其他應用程序。

如果將最大堆大小設置爲(例如)框上的RAM數量,您可以有效地讓VM確定需要多少內存(達到此限制)。問題在於虛擬機可能會有效地削弱正在運行的機器,因爲它會在決定需要垃圾收集之前接管機器上的所有內存。

當您指定最大堆大小時,您對VM所說的內容是,在您需要開始垃圾收集之前,您可以使用此內存量。你不能有更多,因爲如果你採取更多的話,那麼運行在盒子上的其他應用程序將會減速,如果你使用的不止這些,你將開始交換到磁盤。

另請注意,它們是關於內存的兩個值,即「當前堆大小」和「最大堆大小」。當前堆大小是堆大小當前使用的內存大小,如果需要更多,它可以調整堆大小,但不能將堆大小調整爲大於最大堆大小值。

+0

我認爲是服務器,那裏有一個管理員在一個晴朗的答案誰瞭解如何調整JVM(或者至少您可以合理預期這一點)並設置適當的最大值以便與其他進程一起使用。然而,在桌面上你問一個用戶去鼓搗配置文件和啓動腳本,他們有沒有經驗或理解的東西,和Sun目前的答案是 - 用C編寫 – Yishai 2010-01-21 15:11:07

+0

@Yishai一個發射器:太陽VM默認對於大多數應用程序來說相當合理的值,iirc的默認值也會根據可用RAM進行調整。對於默認值有問題的應用程序,安裝腳本可以很容易地創建一個啓動腳本(不是c啓動程序),它可以設置另一個最大值。編輯:順便說一句,我也不喜歡它,我相信如果他們想要,Sun可以刪除它。 – Fredrik 2010-01-21 16:17:22

+0

@Fredrik,如果用戶安裝腳本後增加RAM他們的系統上運行?某些桌面應用程序希望在可用時使用更多可用RAM(例如,用於緩存)。 – Yishai 2010-01-21 18:36:08

2

從IBM的performance tuning tips(因此可能無法直接適用於Sun的虛擬機)

Java堆參數會影響垃圾收集行爲。增加堆大小支持更多的對象創建。因爲大堆需要更長的時間才能填充,所以在垃圾收集發生之前應用程序運行的時間會更長。然而,更大的堆也需要更長的時間來壓縮並導致垃圾回收花費更長時間。

JVM具有用於管理JVM存儲的閾值。達到閾值時,會調用垃圾回收器來釋放未使用的存儲。因此,垃圾收集可能會導致Java性能的顯着下降。在更改初始和最大堆大小之前,應考慮以下信息: 在大多數情況下,應將最大JVM堆大小設置爲高於初始JVM堆大小的值。這允許JVM在初始堆的範圍內的正常穩定狀態期間有效地操作,而且通過將堆擴展到最大JVM堆大小來在高事務量期間有效操作。在某些需要絕對最優性能的罕見情況下,您可能需要爲初始堆大小和最大堆大小指定相同的值。這將消除JVM需要擴展或收縮JVM堆大小時發生的一些開銷。確保區域足夠大以容納指定的JVM堆。 小心使初始堆大小過大。儘管大堆大小最初通過延遲垃圾回收來提高性能,但大堆大小最終會影響響應時間,因爲垃圾收集最終會啓動,因爲收集過程需要更多時間。

所以,我猜你不能在運行時更改值的原因是因爲它可能沒有幫助:或者你的堆有足夠的空間,或者你沒有足夠的空間。一旦用完,GC循環將被觸發。如果這樣不能釋放空間,那麼無論如何你都塞滿了。您需要捕捉OutOfMemoryException,增加堆大小,然後重試您的計算,希望這次您有足夠的內存。

一般來說,除非你需要它,所以,如果你認爲你可能需要擴大在運行時內存,你可以只指定一個較大的最大堆大小VM將不使用的最大堆大小。

我承認這有點不盡人意,似乎有點懶,因爲我可以想象一個合理的垃圾收集策略,當GC未能釋放足夠空間時會增加堆大小。儘管我的想象力轉化爲高性能的GC實現是另一個問題,但是;)

8

歷史上一直存在這種限制的原因,它不允許Applets在瀏覽器中吃掉所有用戶的內存。從來沒有這種限制的微軟VM實際上允許這樣做,這可能導致對用戶計算機的某種拒絕服務攻擊。僅在一年前,Sun在1.6.0 Update 10 VM中引入了一種讓applet指定他們需要多少內存(限於物理內存的某個固定份額)的方法,而不是在計算機上始終將其限制爲64MB有8GB或更多的可用。

現在,由於JVM已經發展,當虛擬機沒有在瀏覽器中運行時,應該有可能擺脫這種限制,但即使存在大量錯誤報告,Sun顯然從未認爲它是如此高優先級的問題已經提交最終允許堆增長。

+1

你是對的,也有錯誤報告要求是:http://bugs.sun.com/view_bug.do?bug_id=4741914,http://bugs.sun.com/view_bug.do?bug_id=4408373 – 2010-01-21 16:29:28

+0

+1這是唯一對我有意義的答案,包括鏈接問題的答案。只需花上幾個小時追逐與Crashplan一個問題,簡單的修復是次數增加只是一個不起眼的參數,在一個不起眼的設置文件。誰選擇了256MB的上限,讓我的備份失敗了幾周而沒有注意到,並且擁有充足的系統內存。 – 2014-09-20 12:38:53

相關問題