JVM内存管理(二):垃圾判定以及垃圾回收算法

1 如何判断一个对象是否是垃圾

1.1 引用计数法

如果一个对象被别的地方引用一次就计数+1、否则-1,等于0的时候代表没有任何引用,可以视为是垃圾,可以被GC。
缺点
就是一个循环引用的问题,比如对象A和对象B相互引用,但是A没有被任何其他除B对象引用,B也没有被任何其他除A对象引用,这就造成了A和B的引用计数都等于1,这就造成了他们都不是垃圾,无法GC。但是实际测试发现A和B都被回收了,那么可以猜测虚拟机HotSpot并没有使用引用计数法作为GC算法。

1.2 可达性分析

如果对象可以从GC Root开始搜索,搜索走过的路径被称为引用链,如果对象不在引用链上,则可以被视为垃圾。如图中红色对象虽然引用计数不为1,但是也被视为垃圾。
可达性分析

可以作为GC Roots的对象

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

可达性分析不可达的对象一定会被gc吗?
答案是不一定的。 当一个对象至少要经历两次标记才会被真正宣告死亡,第一次可达性没有到达的对象,在经历第二次标记前会有一次逃生的机会。如果对象重写了finalize() 方法,并且该方法重新和引用链上的对象建立连接的话,就可以逃脱了。

2 GC算法

2.1 标记-清除(Mark Sweep)

标记清除
该算法主要分为两个阶段:

  1. 第一阶段:标记。将垃圾进行标记,如图中红色;
  2. 第二阶段:清除。将红色对象进行gc。

该算法显而易见的缺点:
就是两阶段比较耗时,效率低下,其次就是产生内存碎片,造成空闲内存的不连续,导致分配不了大对象时候会提前触发gc。

2.2 复制算法

复制算法
将内存分为两块,只用其中一块。将存活对象复制到另一边,清除左边的垃圾对象。

优点和缺点显而易见:
优点:没有内存碎片,内存空间连续。
缺点:浪费一半的内存空间。

2.3 标记-整理(Mark-Compact)

标记-整理
跟标记-清除算法差不多,但是并不是直接清除,而是将存活对象移动到一边,然后再清除掉垃圾对象,优点就是没有了内存碎片。

2.4 分代算法

前面介绍了三种算法,再jvm中堆内存会分为老年代和年轻代,会根据分代特点选择合适的垃圾回收算法。比如年轻代,因为大部分对象都是朝生夕灭,所以采用复制算法,只需要复制少量对象。而老年大对象都是存活时间较长的,所以复制算法不适用,所以选择标记-清理或者标记整理算法进行垃圾回收。


版权声明:本文为weixin_39035120原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。