查看当前机器所使用的垃圾回收器
说明
各种垃圾回收算法都有各自的优缺点。jvm也并没有只采用一种垃圾算法。并提供几种组合供我根据场景进行选择。
jvm内存结构
Person p=new Person();
1.程序里面创建一个对象会向向eden区和from区申请空间
2..当eden区和from区内存紧张则会触发(Scavenge GC)将非垃圾对象复制到to区,并将to区的纯活对象年龄+1(如果to区满了存放不下剩余的纯活对象则会移动到老年代)
3.回收eden区和from区的垃圾对象。并将to和from调换位置
4.后面每次回收纯活对象的年龄都会+1 当年龄到达15则移动到老年代
5.当老年代内存紧张则会触发(Full GC) 回收老年代垃圾对象
因为老年代使用标记清除法,所以会导致程序全局暂停,
比如:
比如一个生日聚会。你一边打扫房间 别人一边制造大量垃圾,会导致垃圾永远清理不完
全局暂停的影响
比如做了主从, 当主机因为全局暂停, 从监测到以为主机挂掉了。这个时候从机切为主机。 这个时候主机执行完清理 重新开始运行程序。这个时候会导致数据不一致问题、
我们在实际中应当合理调节老年代大小
还有前面说了 因为from区和to区容纳不了纯活对象会自动担保放到老年代,会照成本来纯活时间不长的对象 到了老年代。占用老年代内存 导致fullgc 所以 新生代的内存也要根据合理调配。
serial(串行收集器)
特点
最老的一种垃圾回收期 ,稳定,效率高
采用单线程回收
新生代采用复制算法 老年代采用标记压缩算法
当jvm垃圾回收时会"stop then world"短暂的暂停所有用户线程
参数配置
-XX:+UseSerialGC 默认老年代也使用serial收集器 可以单独配置老年代收集器
ParNew
特点
新生代并行回收 老年代串行回收
并行回收需要cpu多核支持
多核cpu的首选,如果单核使用此收集器 性能会低于serial收集器 是Server模式的默认收集器
参数配置
-XX:+UseParNewGC 启用收集器
-XX:ParallelGCThreads设置回收线程数量,一般,最好与 CPU 数量相当,避免过多的线程数影响垃圾收集性能。在默认情况下,当 CPU 数量小于 8 个,ParallelGCThreads 的值等于 CPU 数量,大于 8 个,ParallelGCThreads 的值等于 3+[5*CPU_Count]/8]。以
ParallelScavenge收集器
特点
类似ParNew
参数配置
CMS收集器
特点
老年代收集器
与并行回收收集器不同,CMS 收集器主要关注于系统停顿时间。CMS 是 Concurrent Mark Sweep 的缩写,意为并发标记清除,从名称上可以得知,它使用的是标记-清除算法,同时它又是一个使用多线程并发回收的垃圾收集器。
CMS 工作时,主要步骤有:初始标记、并发标记、重新标记、并发清除和并发重置。其中初始标记和重新标记是独占系统资源的,而并发标记、并发清除和并发重置是可以和用户线程一起执行的。因此,从整体上来说,CMS 收集不是独占式的,它可以在应用程序运行过程中进行垃圾回收。
- 初始标记:为了收集应用程序的对象引用需要暂停应用程序线程,该阶段完成后,应用程序线程再次启动。
- 并发标记:从第一阶段收集到的对象引用开始,遍历所有其他的对象引用。
- 重标记:由于第三阶段是并发的,对象引用可能会发生进一步改变。因此,应用程序线程会再一次被暂停以更新这些变化,并且在进行实际的清理之前确保一个正确的对象引用视图。这一阶段十分重要,因为必须避免收集到仍被引用的对象。
- 并发清理:所有不再被应用的对象将从堆里清除掉。
- 并发重置:收集器做一些收尾的工作,以便下一次GC周期能有一个干净的状态。
缺点
参数设置
G1搜集器
特点:
收集器的目标是作为一款服务器的垃圾收集器,因此,它在吞吐量和停顿控制上,预期要优于 CMS 收集器
与cms相比 G1收集器是采用标记压缩算法 所以不会产生垃圾碎片
参数:
-XX:+UnlockExperimentalVMOptions –XX:+UseG1GC 启用G1收集器
-XX:MaxGCPauseMills=20,-XX:GCPauseIntervalMills=200 可以非常精确的控制停顿时间 停顿时间为20时垃圾收集不超过200
不同收集器性能测试
测试代码
static HashMap map = new HashMap(); public static void main(String[] args){
long begintime = System.currentTimeMillis();
for(int i=0;i<10000;i++){
if(map.size()*512/1024/1024>=400){
map.clear();//保护内存不溢出
System.out.println("clean map");
}
byte[] b1;
for(int j=0;j<100;j++){
b1 = new byte[512];
map.put(System.nanoTime(), b1);//不断消耗内存
}
}
long endtime = System.currentTimeMillis();
System.out.println("运行总耗时:"+(endtime-begintime));
}
serial测试结果
jvm参数:-Xmx512M -Xms512M -XX:+UseSerialGC
ParNew测试结果
jvm参数:-Xmx512M -Xms512M -XX:+UseParNewGC -XX:ParallelGCThreads=6 (按照我们上面设置线程数量原则 我的电脑是6核 所以我设置6)
ParallelScavenge
jvm参数:-Xmx512M -Xms512M -XX:+UseParallelOldGC -XX:ParallelGCThreads=6
jvm参数:-Xmx512M -Xms512M -XX:+UseParallelGC -XX:ParallelGCThreads=6
CMS
jvm参数:-Xmx512M -Xms512M -XX:+UseConcMarkSweepGC -XX:ParallelGCThreads=6
G1收集器
jvm参数:-Xmx512M -Xms512M -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC
注意:不能完全以上面的数据评估收集器好坏。因为每次执行结果都不一样 我只是放出第一次执行结果