JVM 的垃圾回收机制


1、概念

垃圾回收(Garbage Collection,GC),顾名思义就是释放垃圾占用的空间,防止内存泄露。有效的使用可以使用的内存,对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收。


2、问题

  1. 哪些垃圾是需要回收的?
  2. 有哪些重要的垃圾回收算法?
  3. 垃圾回收的具体流程是怎样的?
2.1 哪些垃圾是需要回收的?

判断对象是否需要回收有两种算法。一种是引用计数算法、一种是可达性分析算法。

引用计数算法

引用计数算法很简单,它通过记录对象被引用的次数从而判断该对象的重要程度。如果该对象被其它对象引用,则它的引用计数加一,如果删除对该对象的引用,那么它的引用计数就减一,当该对象的引用计数为0时,那么该对象就会被回收。

引用计数存在什么问题呢?当有两个对象相互引用时,由于它们互相引用对方所以计数都不为零,这就会导致这两个对象无法回收。

例如:

public class ReferenceCountingGC {
  public Object instance;
  public ReferenceCountingGC(String name) {
  }
  public static void testGC(){
    ReferenceCountingGC a = new ReferenceCountingGC("objA");
    ReferenceCountingGC b = new ReferenceCountingGC("objB");
    a.instance = b;
    b.instance = a;
    a = null;
    b = null;
  }
}

我们可以看到,最后这2个对象已经不可能再被访问了,但由于他们相互引用着对方,导致它们的引用计数永远都不会为0,通过引用计数算法,也就永远无法通知GC收集器回收它们。
所以,Java虚拟机采用的是另一种方法来判断对象是否存活,它就是可达性分析算法。


可达性分析算法

可达性分析算法,首先要确定一系列根对象(GC Roots),并从根对象为起点根据对象之间的引用关系搜索出一条引用链(Reference Chain),在引用链的对象就存活,而不在引用链的对象就认定为可回收对象。

有一个比喻十分恰当:可达性分析算法就好比是在清洗葡萄串,我们可以从一根枝提起一大串葡萄,他们就像一串引用链,而没有和引用链相连的对象就像是散落在池子里的葡萄,可以回收。

Java内存区域中可以作为GC ROOT的对象:

  1. 虚拟机栈中引用的对象(正在运行的方法使用到的变量、参数等)

  2. 方法区中类静态属性引用的对象(static关键字声明的字段)

  3. 方法区中常量引用的对象,(也就是final关键字声明的字段)

  4. 本地方法栈中引用的对象(native方法)

  5. Java虚拟机内部的引用。(系统内部的东西当然能作为根了)


2.2 有哪些重要的垃圾回收算法?

标记清除算法

标记-清除法是最基本的一种垃圾回收算法,总的来说分为两步:
· 标记
JVM 的垃圾回收机制_第1张图片

标记所有需要回收的对象(灰色),也就是在做垃圾的判定。

· 清除
JVM 的垃圾回收机制_第2张图片

将标记为灰色的部分,清除掉。

需要注意的是:所谓的清除,并不需要真正地把整个内存的字节进行清零操作,只需要把空闲对象的起始结束地址记录下来放入空闲列表里,表示这段内存是空闲的就行。

优点速度快,只需要做个标记就能知道哪一块需要被回收,但是他的缺点也是致命的。

主要缺点有两个:一是执行效率不稳定,二是会涉及到内存碎片化的问题。

上面所描述的这个栈,通过标记清除法虽然是清除了空间,但是清除出来的内存是大量的不连续内存碎片,像下面的这块对象,明明整体都有位,却因为不连续无法放入,这是标记-清除算法最大的缺点。
JVM 的垃圾回收机制_第3张图片


标记整理算法

与标记-清除算法不同,标记-整理算法是移动式的。他会让所以存活的对象都向内存空间一端移动,然后清除到边界以外的内存。

·标记
JVM 的垃圾回收机制_第4张图片

·移动
JVM 的垃圾回收机制_第5张图片


标记-复制算法

标记-复制算法,相比前面的比较不同,他将内存空间分为两块,在垃圾回收时将正在使用的内存中的存活对象复制到未被使用的内存块中,然后呢再清除正在使用的内存块中的所有对象。最后再交换两个内存的角色,最后完成垃圾回收。
大体来看可以分为 这么几个步骤:

·复制

JVM 的垃圾回收机制_第6张图片

·清空
JVM 的垃圾回收机制_第7张图片

·易位
JVM 的垃圾回收机制_第8张图片

不难看出,标记复制算法不需要标记算是提升了效率。此外他也不会参数碎片问题。

但是。标记复制算法的缺点也是十分明显的,它需要双倍空间。


文章来源:[漫画:什么是JVM的垃圾回收](https://blog.csdn.net/bjweimengshu/article/details/117677385)

你可能感兴趣的:(Java后端,jvm.gc,jvm,垃圾回收)