一個可以提升JVM執行效能的引數
JAVA程序啟動的時候,雖然我們可以為JVM指定合適的記憶體大小,但是這些記憶體作業系統並沒有真正的分配給JVM,而是等JVM訪問這些記憶體的時候,才真正分配,這樣會造成以下問題:
- 第1次YGC之前Eden區分配物件的速度較慢;
- YGC的時候,Young區的物件要晉升到Old區的時候,這個時候需要作業系統真正分配記憶體,這樣就會加大YGC的停頓時間;
啟動時間
配置 -XX:+AlwaysPreTouch 引數可以優化這個問題,不過這個引數也有副作用,它會影響啟動時間,那影響到底有多大呢?請接著往下看。

對比結果如下,差距還是蠻大的:
~ | -XX:+AlwaysPreTouch | XX:-AlwaysPreTouch(default) |
---|---|---|
16G | 36s | <1s |
8G | 20s | <1s |
並行PreTouch
配置這個引數後這麼耗時其中一個原因是,這個特性在JDK8版本以前都不是並行處理的,到了JDK9才是並行。可以戳連結Parallelize Memory Pretouch: https://bugs.openjdk.java.net/browse/JDK-8157952
根本原因
配置-XX:+AlwaysPreTouch引數後,JVM程序啟動時間慢了幾個數量級的根本原因呢?
在沒有配置-XX:+AlwaysPreTouch引數即預設情況下,JVM引數-Xms申明的堆只是在虛擬記憶體中分配,而不是在實體記憶體中分配:它被以一種內部資料結構的形式記錄,從而避免被其他程序使用這些記憶體。這些記憶體頁直到被訪問時,才會在實體記憶體中分配。當JVM需要記憶體的時候,作業系統將根據需要分配記憶體頁。
配置-XX:+AlwaysPreTouch引數後,JVM將-Xms指定的堆記憶體中每個位元組都寫入'0',這樣的話,除了在虛擬記憶體中以內部資料結構保留之外,還會在實體記憶體中分配。並且由於touch這個行為是單執行緒的,因此它將會讓JVM程序啟動變慢。所以, 要麼選擇減少接下來對每個快取頁的第一次訪問時間,要麼選擇減少JVM程序啟動時間,這是一種trade-off 。

對G1無效
G1前提下,即使配置了-XX:+AlwaysPreTouch引數,JVM也會忽略掉這個引數,即跟沒有配置效果一樣。8u60版本修復了這個問題,詳情請戳連結:G1 ignores AlwaysPreTouch: https://bugs.openjdk.java.net/browse/JDK-8067469 ,如下圖所示:

轉自 阿飛的部落格