探究执行System.gc()以及finalize对于垃圾回收的影响

System.gc()

在默认情况下,执行System.gc()会显示的触发FullGC,同时对新生代以及老年大产生影响,进行回收。
其实在正常情况下,垃圾回收都是自动进行的,无需人为主动触发,因为频繁的触发垃圾回收对整体系统来说时没有好处的,因此虚拟机会提供一个参数DisableExceptionGC来控制是否手工触发GC的。

我们可以看以下具体的实现:

Runtime.getRuntime().gc();

内部是一个native方法:

public native void gc();

我们可以看下C++源码:

image

可以看到,其实是通过判断DisableExplicitGC这个参数去判断是否进行垃圾回收的,所以我们可以i设置: -XX:-+DisableExplicitGC,条件判断就无法成立,那么就会用显示GC,使得System.gc等价于一个空函数调用。

同时,当我们使用System.gc的时候,如果垃圾回收器是CMS或者G1的话,默认是不会执行并发的方式进行回收的,这时候我们需要打开虚拟机参数:

-xx:+ExplicitGCInvokesConcurrent 该参数,可以在使用CMS或者G1时,如果触发system.gc,会并发的执行垃圾回收。

finalize对于垃圾回收的影响

在java中提供了一个类似C++析构函数的机制===finalize

protected void finalize() throws Throwable { }

可以看到,该方法设置成protected,可以用于子类重写,用于在对象倍回收时进行资源的释放。

在目前,普遍的认识是尽量不要使用finalize函数进行资源释放,原因如下:

1.在finalize时可能会导致对象复活,在finalize函数执行之前,可能在系统中对象的引用已经倍清楚了,但是作为实例方法finalize,对象的this引用依然会被传入方法内部,如果引用外泄,对象就会复活,此时对象又会变成可触及状态。

2.finalize的执行时间是不能保证的,完全由gc线程决定,因此极端情况下,若不发生gc,则将没有己会执行。推荐在try catch finally中释放。

函数finalize是由FinalizerThread线程处理的,每一个即将被回收的并且包含有finalize方法的对象都会在正式回收前加入FinalizerThread的执行队列,该队列是引用队列,内部实现为链表结构。


image

Finalizer内部封装了实际的回收对象,referent字段则指向实际的对象引用。


image

由于对象在回收之前被Finalizer的referent字段进行强引用,并加入了FinalizerThread的执行队列,这意味着对象又变为可达性对象,因此阻止了对象的正常回收。

由于在引用对象中的元素排队执行finalize方法,一旦出现性能问题,将导致这些垃圾对象长时间堆积在内存中,可能导致OOM异常。

image

部分取材自: 《实战java虚拟机》
《深入理解jvm虚拟机》

你可能感兴趣的:(探究执行System.gc()以及finalize对于垃圾回收的影响)