【JVM】垃圾回收算法
【JVM】垃圾回收算法
Java
是一种高级语言,它不需要C
语言那样由程序员手动开辟内存,用完之后手动释放内存,Java
有自己的垃圾回收器,对于内存中的那些不使用的对象,垃圾收集器会自动回收,垃圾回收的时候使用不同的算法,针对不同的场景使用不同的算法,以达到提升回收效率的效果。
在JVM
中主要有三种垃圾回收算法,标记清除、标记整理、复制算法。
标记清除(Mark Sweep)
标记清除分为两个阶段,标记和清除。
我们假设内存中目前的内存分配如下:
可以看到绿色和红色对象由于有GC Root
关联,通过可达性分析可知是不应该被回收的,所以标记他们,但是蓝色对象object4
和object6
是应该被回收的。
标记阶段:会从根节点出发遍历对象关系,对访问过的对象打赏标记,标记为不可回收,也就是对象可达。
清除阶段:会对未标记的对象进行清理,将内存还回,这样被还回的空间就能够重新被使用。
回收完毕后内存情况就变为如下图所示:
两个红色中间的部分就是本次GC后被释放的部分。
标记清除算法的缺点就是会导致内存碎片问题。
因为回收的内存是不连续的,可能会导致内存碎片问题,这可能会降低内存的使用率,比如被回收的内存是10KB
,那么说明最大就能容纳10KB
的对象,如果想放比10KB
大的对象,是放不进去的,这也会导致可能出现频繁的垃圾回收。
标记整理(Mark Compact)
标记整理也是分为两个阶段,标记和整理。
标记阶段:这里的标记和标记清除里的标记是一样的,都是标记出来可达的对象。
整理阶段:整理阶段其实就是解决标记清除算法带来的碎片问题,因为在清除的时候,会将可用的对象移动,使其紧凑,这样就不会出现内存碎片。
移动完毕后就变为了下如这样
此时内存中就没有碎片了,新对象可以在后面继续分配内存。
标记整理算法显然没有内存碎片了,但是他也是有缺点的,由于整理是将对象移动,内存地址就会变化,变量引用肯定也要变化。那么这个效率肯定是低一些的。
复制算法(Copy)
复制算法是将内存分为大小相等的两部分,一部分叫做FROM
区,另一部分叫做TO
区。复制算法首先也是标记那些存活的可达对象,标记的操作跟之前两种算法没有区别。标记后将标记的对象拷贝到另一个区域内,比如对象在FROM
区,就拷贝到TO
区。
复制完毕后,就可以将FROM
区清理掉,并且FROM
和TO
互换。
在复制算法中TO
区域总是空间的空间。
复制算法的有点也是不会产生碎片,它也是有缺点的:内存被分为两半,总是有一半是空闲的,所以内存利用率就第了。空闲的内存其实挺浪费的。
总结
三种算法在不同的垃圾收集器中都会使用,只不过根据不同的情况采用不同的垃圾算法而已,不同的垃圾回收器选择了不同的算法,也应对了不同的情况,择优选择。