垃圾回收算法

【JVM】垃圾回收算法

Java是一种高级语言,它不需要C语言那样由程序员手动开辟内存,用完之后手动释放内存,Java有自己的垃圾回收器,对于内存中的那些不使用的对象,垃圾收集器会自动回收,垃圾回收的时候使用不同的算法,针对不同的场景使用不同的算法,以达到提升回收效率的效果。

JVM中主要有三种垃圾回收算法,标记清除、标记整理、复制算法。

标记清除(Mark Sweep)

标记清除分为两个阶段,标记和清除。

我们假设内存中目前的内存分配如下:

内存情况

可以看到绿色和红色对象由于有GC Root关联,通过可达性分析可知是不应该被回收的,所以标记他们,但是蓝色对象object4object6是应该被回收的。

标记阶段:会从根节点出发遍历对象关系,对访问过的对象打赏标记,标记为不可回收,也就是对象可达。

清除阶段:会对未标记的对象进行清理,将内存还回,这样被还回的空间就能够重新被使用。

回收完毕后内存情况就变为如下图所示:

清理后

两个红色中间的部分就是本次GC后被释放的部分。

标记清除算法的缺点就是会导致内存碎片问题。

因为回收的内存是不连续的,可能会导致内存碎片问题,这可能会降低内存的使用率,比如被回收的内存是10KB,那么说明最大就能容纳10KB的对象,如果想放比10KB大的对象,是放不进去的,这也会导致可能出现频繁的垃圾回收。

标记整理(Mark Compact)

标记整理也是分为两个阶段,标记和整理。

标记阶段:这里的标记和标记清除里的标记是一样的,都是标记出来可达的对象。

整理阶段:整理阶段其实就是解决标记清除算法带来的碎片问题,因为在清除的时候,会将可用的对象移动,使其紧凑,这样就不会出现内存碎片。

移动对象

移动完毕后就变为了下如这样

整理后

此时内存中就没有碎片了,新对象可以在后面继续分配内存。

标记整理算法显然没有内存碎片了,但是他也是有缺点的,由于整理是将对象移动,内存地址就会变化,变量引用肯定也要变化。那么这个效率肯定是低一些的。

复制算法(Copy)

复制算法是将内存分为大小相等的两部分,一部分叫做FROM区,另一部分叫做TO区。复制算法首先也是标记那些存活的可达对象,标记的操作跟之前两种算法没有区别。标记后将标记的对象拷贝到另一个区域内,比如对象在FROM区,就拷贝到TO区。

存货对象FROM复制到TO区

复制完毕后,就可以将FROM区清理掉,并且FROMTO互换。

image-20230907194356627

在复制算法中TO区域总是空间的空间。

复制算法的有点也是不会产生碎片,它也是有缺点的:内存被分为两半,总是有一半是空闲的,所以内存利用率就第了。空闲的内存其实挺浪费的。

总结

三种算法在不同的垃圾收集器中都会使用,只不过根据不同的情况采用不同的垃圾算法而已,不同的垃圾回收器选择了不同的算法,也应对了不同的情况,择优选择。

标签: 垃圾回收算法

添加新评论