首先需要注意的是在對JVM內存調優的時候不能只看操作系統級別Java進程所占用的內存,這個數值不能準確的反應堆內存的真實占用情況,因為GC過后這個值是不會變化的,因此內存調優的時候要更多地使用JDK提供的內存查看工具,比如JConsole和Java VisualVM。
對JVM內存的系統級的調優主要的目的是減少GC的頻率和Full GC的次數,過多的GC和Full GC是會占用很多的系統資源(主要是CPU),影響系統的吞吐量。特別要關注Full GC,因為它會對整個堆進行整理,導致Full GC一般由于以下幾種情況:
舊生代空間不足
調優時盡量讓對象在新生代GC時被回收、讓對象在新生代多存活一段時間和不要創建過大的對象及數組避免直接在舊生代創建對象
Pemanet Generation空間不足
增大Perm Gen空間,避免太多靜態對象
統計得到的GC后晉升到舊生代的平均大小大于舊生代剩余空間
控制好新生代和舊生代的比例
System.gc()被顯示調用
垃圾回收不要手動觸發,盡量依靠JVM自身的機制
調優手段主要是通過控制堆內存的各個部分的比例和GC策略來實現,下面來看看各部分比例不良設置會導致什么后果
1)新生代設置過小
一是新生代GC次數非常頻繁,增大系統消耗;二是導致大對象直接進入舊生代,占據了舊生代剩余空間,誘發Full GC
2)新生代設置過大
一是新生代設置過大會導致舊生代過小(堆總量一定),從而誘發Full GC;二是新生代GC耗時大幅度增加
一般說來新生代占整個堆1/3比較合適
3)Survivor設置過小
導致對象從eden直接到達舊生代,降低了在新生代的存活時間
4)Survivor設置過大
導致eden過小,增加了GC頻率
另外,通過-XX:MaxTenuringThreshold=n來控制新生代存活時間,盡量讓對象在新生代被回收
由內存管理和垃圾回收可知新生代和舊生代都有多種GC策略和組合搭配,選擇這些策略對于我們這些開發人員是個難題,JVM提供兩種較為簡單的GC策略的設置方式
1)吞吐量優先
JVM以吞吐量為指標,自行選擇相應的GC策略及控制新生代與舊生代的大小比例,來達到吞吐量指標。這個值可由-XX:GCTimeRatio=n來設置
2)暫停時間優先
JVM以暫停時間為指標,自行選擇相應的GC策略及控制新生代與舊生代的大小比例,盡量保證每次GC造成的應用停止時間都在指定的數值范圍內完成。這個值可由-XX:MaxGCPauseRatio=n來設置