GC是一個老生常談的問題,但是從現在的開發角度看GC帶來的意義是什麼,是硬件的上限難以提高,從軟件的角度上,來提高硬件的使用率
JVM的GC其實一直都是在內存的整理效果和GC造成的CPU時間損失中博弈。
所以帶來了不同的GC收集器
新生代收集器:Serial、ParNew、Parallel Scavenge
老年代收集器:CMS、Serial Old、Parallel Old
整堆收集器: G1 ZGC
幾個相關概念:
並行收集:指多條垃圾收集線程並行工作,但此時用戶線程仍處於等待狀態。
併發收集:指用戶線程與垃圾收集線程同時工作(不一定是並行的可能會交替執行)。用戶程序在繼續運行,而垃圾收集程序運行在另一個CPU上。
吞吐量:即CPU用於運行用戶代碼的時間與CPU總消耗時間的比值(吞吐量 = 運行用戶代碼時間 / ( 運行用戶代碼時間 + 垃圾收集時間 ))。例如:虛擬機共運行100分鐘,垃圾收集器花掉1分鐘,那麼吞吐量就是99%
FULL GC,串行垃圾回收會使用應用停頓,響應用戶時間長
以前的常用幾種GC可以看這篇文章
https://www.cnblogs.com/chenpt/p/9803298.html
最新的ZGC可以看這篇
https://www.colabug.com/2020/0114/6846387/amp/
這裏我主要是來測試一下各種GC的不同效果。
G1GC,的確性能會好很多,YGC太久也會涼,FGC太久也會涼。感覺咋都涼,哈哈。
代碼在最後面
jvm配置爲
-Xms16m -Xmx32m -XX:+PrintCommandLineFlags
當前默認結果
-XX:InitialHeapSize=16777216 -XX:MaxHeapSize=33554432 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
可以看到是ParalleGC的結果
現在結果就是7S FGC 36次 YGC 26528次
我現在增加 -XX:+UseParNewGC 看看
現在結果就是14S FGC 0次 YGC 58469次
-XX:+UseParallelGC:選擇垃圾收集器爲並行收集器。此配置僅對年輕代有效。可以同時並行多個垃圾收集線程,但此時用戶線程必須停止。( 關注吞吐量)
-XX:+UseParNewGC:設置年輕代爲多線程收集。可與CMS收集同時使用。在serial基礎上實現的多線程收集器。(關注響應時間)
使用 -XX:+UseParallelOldGC 配置
結果 FGC36次 YGC26527 總共6.8S 大概和之前的ParalleGC差不多,這也和定義相差不大,只是FGC多線程,也可能是我CPU多核性能更好。
最基礎的CMS配置
-XX:+UseConcMarkSweepGC
-XX:InitialHeapSize=16777216 -XX:MaxHeapSize=33554432 -XX:MaxNewSize=11186176 -XX:MaxTenuringThreshold=6 -XX:NewSize=11186176 -XX:OldPLABSize=16 -XX:OldSize=22368256 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseConcMarkSweepGC -XX:-UseLargePagesIndividualAllocation -XX:+UseParNewGC
結果FGC 0 YGC 29644,總共7.5S
G1GC
-XX:+UnlockExperimentalVMOptions -XX:+UseG1GC
-XX:InitialHeapSize=16777216 -XX:MaxHeapSize=33554432 -XX:+PrintCommandLineFlags -XX:+UnlockExperimentalVMOptions -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseG1GC -XX:-UseLargePagesIndividualAllocation
結果FGC0 YGC13927 6.468s,性能暫時顯示最好
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import javax.smartcardio.CardTerminal;
import java.lang.reflect.Method;
import java.util.HashMap;
public class JvmGCTest {
public static void main(String[] args) throws Exception {
JvmGCTest jmTest = new JvmGCTest();
jmTest.outOfMemoryTest();//out memory
}
public void outOfMemoryTest() throws InterruptedException {
for(int threadCount=0;threadCount<10;threadCount++){
new Thread(new Runnable() {
@Override
public void run() {
int i = 0;
while (true) {
HashMap<String, TestNoStaticObject> map = new HashMap<>();
//System.out.println(i);
map.put(String.valueOf(i), new TestNoStaticObject());
i++;
if(i>=100000000){
break;
}
if (i <= 100) {
try {
Thread.sleep(100);
} catch (Exception e){
e.printStackTrace();
}
}
}
}
}).start();
}
}
public class TestNoStaticObject {
private double a = 34.53;
private Integer b = 9999999;
public TestNoStaticObject() {
}
}
}