常见面试题如上,垃圾回收算法有4种(引用计数,复制拷贝,标记清除,标记整理)。
那么,垃圾回收器谈谈你的理解:
俗称:串行回收,并行回收,并发标记清除,G1. 垃圾回收的方式:串行,并行,并发,g1.截至到java10,说这个都没问题。
java11.12又多了一种叫zgc。目前讲解以java8为例,先讲这四种。
串行垃圾回收器:为单线程环境设计且只使用一个线程进行垃圾回收,会暂停所有的用户线程,所以不适合服务器环境。
回收可视化效果如下:蓝色为程序执行,黄色为垃圾回收,当发生垃圾回收的时候,正常的程序线程要被暂停。
并行垃圾回收器:多个垃圾回收线程并行工作,此时用户线程是暂停的,适用于科学计算,大数据处理首台处理等弱交互场景。
回收可视化过程如下:
并发垃圾回收器:用户线程和垃圾回收线程同时执行(不一定是并行,可能是交替执行),不需要停顿用户线程,互联网公司多用他,适用对响应时间有要求的场景。
回收过程可视化:
G1:是garbage first的缩写。从java7开始论证,java8就可以使用了,历经了10年的精心准备和论证。从java9开始,默认的垃圾回收方式就是g1.java11又变成了zgc。G1了垃圾回收器将堆内存分割成不同的区域然后并发的对其进行垃圾回收。
截至到java8,主要是这三种垃圾回收器。截止到java8,包括java8如果是互联网公司,都会改成CMS。
天上飞的理念,需要地上跑的实现。垃圾回收算法是思想,需要去落地。
本篇博客的内容是对上述的思想进行继续深化,继续落地实现。也就是具体的垃圾回收器。
可以查看openjdk的源码:
上面有6种,第七种已经被废弃和淘汰了叫做serialOldGC。一共是7种。
G1可以覆盖young和old区,都可以覆盖。
打错号的可以不用了。
defnew:默认新生代垃圾回收器。
tenured:老年代用的垃圾回收器。
parnew:在新生代用并行回收。
psyoungGen:在新生代使用并行垃圾回收器。
paroldgen:在老年区域使用并行垃圾回收。
一旦配置了新生代的垃圾回收机制,老年代就自动配置了,比如:新生代是串行,老年代就是串行。
代码演示:
vm参数:堆空间10m,打印gc细节,打印简单版的jvm参数,使用串行垃圾回收器。
代码:
运行效果:
设置串行垃圾回收器之后,新生代就会用默认的串行垃圾回收器DefNew。养老带用的也是串行垃圾回收器。参考下图的连线。
这个只改变新生代为并行的模式,老年代还是串行的。最佳实践可以看下图的连线,配合老年代的CMS。
修改vm参数为下图:
跟上面同样的代码的运行结果:
确实改变了垃圾回收器为parNewGC。
新生代的GC方式改为了ParNew的gc方式。新生代从串行收集变成了并行收集。
养老区没发生改变,还是串行垃圾回收,但是jvm提示已经废弃了,看下图的红字。
言下之意,并行新生代+串行老年代已经不推荐使用了,看下图:
总结一下上面两个垃圾回收器:
新生代单线程+老年代单线程----->serial
新生代多线程+老年代单线程----->ParNew
java8安装之后,使用的是parallel Scavenge 收集器。他是这样的:
新生代多线程+老年代多线程----->Parallel Scavenge
详细介绍:
为啥会互相激活呢?可以看jdk的源码,这种组合的策略是或者的关系,他俩走的是一个逻辑,所以可以互相激活。
代码演示,vm参数:
运行截图:新生代是并行GC,老年代也是并行GC。这就是parallelgc的具体的执行策略。
随着jdk版本的更迭,为了保证吞吐量,垃圾回收器进行了优化。
设置vm参数:
对于java8,默认就是这个,不用加了。对于java8,parallel收集器和parallelOld收集器是互相激活的。
运行代码,查看控制台结果:
新生代=并行,老年代=并行。java8不做配置,也是这套东西。
CMS是标记清除算法的垃圾回收器实现。
详细介绍:
简单来说,互联网公司,做优化的话,就应该配置成CMS收集器。
注意看下图的连线,说明了这个组合。
结合上面2图,第一步初始标记是停顿的。
第二步,并发标记,和用户线程一起,不需要停顿。
第三步:重新标记,需要暂停。
第四步:并发清除
执行结果如下:
这种配置方法完成了下图的组合:新生代还是ParNew,老年代是CMS。
底层代码:
实际代码就是设置vm参数。
故意配置一下多个垃圾回收器,会如何呢?
第一组实验结果:实际跟配置一个效果一样。
第二组实验结果:也是跟只配置cms一样。