JVM垃圾回收机制

JVM GC回收哪个区域内的垃圾?

JVM GC只回收堆区和方法区内的对象
虚拟机栈、程序计数器、本地方法栈为线程私有,不需要回收

JVM GC什么时候执行?

伊甸区满的时候,执行Young GC
老年区满的时候,执行Full GC

如何判断一个对象是否可以被回收?

1、引用计数法(有缺陷,无法解决循环引用问题,JVM 没有采用)
2、可达性分析(解决了引用计数的缺陷,被 JVM 采用)

什么是引用计数法?

对象被引用一次,计数器+1,失去引用,计数器-1,当计数器在一段时间内为0时,即认为该对象可以被回收了。
(无法解决相互引用的问题,例如:A引用B,B引用A,它们永远都不会再被使用)

什么是可达性分析?

通过一系列的称为 “GC Roots” 的对象作为起始点,从这些节点开始向下搜索,所有所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连时,则证明此对象是不可用的

Java中可以作为GC ROOT的对象有哪些?

1、虚拟机栈中引用的对象(本地变量表)
2、方法区中静态属性引用的对象
3、方法区中常量引用的对象
4、本地方法栈中引用的对象(Native对象)

JVM中将对象的引用分为了四种类型

1、强引用:new出来的对象都是强引用,GC无论如何都不会回收,即使抛出OOM异常。
2、软引用:只有当JVM内存不足时才会被回收。
3、弱引用:只要GC,就会立马回收,不管内存是否充足。
4、虚引用:可以忽略不计

什么是分代回收?

对于新生代内存的回收使用Young GC主要采用复制算法。
而对于老年代的回收使用Full GC,大多采用标记-整理算法。

为什么需要分带回收?

JVM为了优化对内存的回收

常见的GC算法

1、复制(停止-复制 效率低,需要的空间大,优点,不会产生碎片)
2、标记-清除(标记 - 清除算法 速度较快,占用空间少,标记清除后会产生大量的碎片)
3、标记-压缩(在标记-清除的基础上移动数据,避免产生内存碎片)

复制算法

复制算法采用的方式为从根集合进行扫描,将存活的对象移动到一块空闲的区域
当存活的对象较少时,复制算法会比较高效(新生代的Eden区就是采用这种算法)

标记-清除

该算法采用的方式是从根集合开始扫描,对存活的对象进行标记,标记完毕后,再扫描整个空间中未被标记的对象,并进行清除。标记-清除动作不需要移动对象,且仅对不存活的对象进行清理,在空间中存活对象较多的时候,效率较高,但由于只是清除,没有重新整理,因此会造成内存碎片。

标记-压缩

该算法与标记-清除算法类似,都是先对存活的对象进行标记,然后清除未被标记的对象,但是在清除后会把活的对象向左端空闲空间移动,然后再更新其引用对象的指针,该算法避免了标记-清除的碎片问题,但由于需要进行移动,因此成本也增加了。(该算法适用于老年代)

垃圾回收器简介

每一个回收器都存在Stop The World 的问题,只不过各个回收器在Stop The World 时间优化程度、算法的不同

常见的垃圾收集器

1、Serial	(新生代)
2、ParNew	(新生代)
3、ParallelScavenge(新生代)
4、SerialOld	(老年代)
5、ParallelOld(老年代)
6、CMS	(老年代)
7、G1	(新生代和老年代)

CMS的一大特点,就是用两次短暂的暂停来代替串行或并行标记整理算法时候的长暂停。
CMS的缺点
1、内存碎片
2、需要更多的CPU资源
3、需要更大的堆空间
G1既可以回收新生代,又可以回收老年代

原文地址:https://www.cnblogs.com/jis121/p/11046318.html