Windows 上的 JVM - 分頁和完整 GC
我們有一個在 Windows (Server 2012 R2) 上執行的基於 Java 的應用程序(TeamCity,在 Tomcat 上,在 Java 1.7 上)。Java 以 6GB 的最大堆大小執行,系統具有 10GB 的 RAM。它是機器上唯一執行的非作業系統服務。
對於穩定狀態,一切都很好。不幸的是,當 Java 偶爾進行一次 full GC 時,我們發現 Java 堆的一部分已被分頁,需要重新分頁,因此 GC 需要幾分鐘而不是幾秒鐘。
一般的智慧永遠不會完全禁用 Windows 頁面文件,但我想知道這是否是一個反例?(我們真的不希望世界在它為 GC 分頁時暫停幾分鐘!)
鑑於高 IO 工作負載導致 Windows 驅逐一些堆以支持磁碟記憶體,是否有更好的方法來確保 JVM 永遠不會被分頁到磁碟?
謝謝,羅伯
呃,爪哇。:(
首先我給你一個簡短的回答:是的,我認為這可能是在沒有頁面文件的情況下執行的正當理由,當然知道你將不再能夠生成系統崩潰轉儲,並且你的機器將崩潰或不穩定到你希望它在記憶體不足時崩潰的程度。但是,您只需要自己權衡利弊。從技術上講,Windows 可以在沒有頁面文件的情況下正常執行,只要您不將其執行到記憶體不足……例如,除非舊的或設計不佳的應用程序愚蠢地假設存在頁面文件。
現在,長答案。
首先,為什麼會發生分頁?作業系統使用頁面替換算法,其中每個記憶體頁面都標有“年齡”,這是自上次訪問該記憶體頁面以來的計數器。長時間未訪問的記憶體頁面最終會寫入磁碟,以便其他可能更重要的數據可以在 RAM 中獲得空間。如果一個程序更頻繁地主動使用其分配的記憶體,那麼這些頁面被寫出到頁面文件的機會就更少了。
應用程序開發人員可以呼叫
VirtualLock
Windows API 函式來要求 Windows 將頁面鎖定到呼叫程序的工作集中。但是,它需要一定的作業系統特權才能成功呼叫該函式,因為如果您玩得不好,將頁面鎖定到 RAM 中可能會對整個系統產生不利影響。但這對您沒有幫助,因為VirtualLock
您在開發應用程序時會在程式碼中使用它。這不是您可以在其他人的執行過程中呼叫的東西。但是對於 Java,現在您在實際作業系統及其記憶體管理器之上執行具有自己的內部記憶體管理器的虛擬機,並且正如您所體驗的那樣,這兩者並不總是可以很好地協同工作。將程序(或更準確地說,將程序分配的所有記憶體)鎖定到物理記憶體中是特定於作業系統的,因此,Java 不會處理這些事情,因為 Java 力求做到不可知和跨界。平台。
因此,我所知道的讓 Java 將其分配鎖定到 RAM 以便它們不會被分頁的唯一方法是使用 JNI(Java 本機介面)和
mlock()
/mlockall()
。