1、垃圾回收器的選擇
低延遲:CMS、G1、ZGC
高吞吐量:ParallelGC
2、最快的GC是不發生GC
數據是不是太多,例如:在查詢大表的數據時,添加limit進行限制
對象的使用:用哪一個對象就查哪一個對象
對象的大小:能用基本類型就不用包裝類型,例如:Integer占用24字節,而int占用4字節
代碼中是否存在內存泄漏
3、新生代調優
(1)新生代特點
所有的new操作的內存分配非常廉價
死亡對象的回收代價是零(復制的是存活的對象,死亡的對象直接清除了)
大部分對象用過即死
Minor GC的時間遠遠低於Full GC
(2)新生代是不是越大越好
較小的話易發生Minor-GC,Minor-GC的時候會出現STW造成時間增加
較大的話,老年代的內存就會變小,易發生垃圾回收(Full-GC),暫停時間要比新生代的暫停時間更長
Oracle建議的新生代內存大小為:占用堆內存的百分之25-百分之50
新生代的復制算法分為標記和復制兩個階段,復制要花費的時間更多,新生代的對象只有少量的對象能夠存活,因此,復制的時間較少,即使新生代有較大的內存,回收的效率依舊不會太高
(3)幸存區
幸存區要能夠保留:當前活躍對象和需要晉升的對象
幸存區的晉升閾值設置要合理,閾值太大的話,幸存區的幸存對象會被多次復制,閾值過小的話,晉升后的對象進入老年帶后就只有Full-GC的時候才會被清理
4、老年代
以CMS為例:
CMS的老年代內存越大越好:
因為垃圾處理線程和用戶的線程是並發的,當垃圾處理的時候,用戶的線程還會產生垃圾(浮動垃圾),如果再次導致內存不足,就會導致並發失敗。退化為Serial-old,串行的垃圾回收器,響應時間較長
先嘗試不去調優,因為如果未發生Full-GC,則證明老年代的內存正常,可以嘗試調優新生代
如果老年代發生了Full-GC,就去觀察發生Full-GC的時候老年代的內存占用,將老年代的內存預設調大1/4-1/3
5、案例
(1)案例一:FullGC和MinorGC頻繁
原因分析:業務高峰期的時候,大量的對象被創建,導致新生代空間不足,MinorGC頻繁。對象的晉升閾值也隨之降低,導致老年代中生存周期並不是很長的對象晉升,老年代就需要頻繁地進行Full-GC
解決方案:嘗試增加新生代內存,並增加幸存區晉升的閾值
(2)請求高峰期發生Full GC,單次暫停時間特別長(CMS)
重新標記的時候要掃描整個堆內存,耗時較多,可以在重新標記以前對新生代先做一次垃圾回收減少對象的數量
可以添加虛擬機參數:-XX:CMSScavengeBeforeRemark
(3)老年代充裕的情況下,發生Full GC(CMS jdk1.7)
jdk1.8將元空間作為方法區的實現,jdk1.7將永久代作為方法區的實現,永久代空間的不足也會引起Full GC