深入分析Object.finalize方法的实现原理
2018-01-17 21:42
1276 查看
原文地址:http://www.importnew.com/23913.html
从gc日志中可以看出来,执行完
执行完成gc日志如下:
和之前的gc日志进行比较,发现
对象的初始化过程会对
其中
在jvm中通过
如果返回了
通过
当
pending字段什么时候会被设置?在GC过程的引用处理阶段,通过
这么做主要是为了确保在用户忘记手动关闭
finalize
如果类中重写了finalize方法,当该类对象被回收时,
finalize方法有可能会被触发,下面通过一个例子说明
finalize方法对垃圾回收有什么影响。
Block类中声明一个占用内存200M的数组,是为了方便看出来gc之后是否回收了
Block对象,执行完的gc日志如下:
从gc日志中可以看出来,执行完
System.gc()之后,
Block对象被如期的回收了,如果在
Block类中重写了
finalize方法,会是一样的结果么?
和之前的gc日志进行比较,发现
finalize方法确实被触发了,但是
Block对象还在内存中,并没有被回收,这是为什么?下面对
finalize方法的实现原理进行分析。
finalize实现原理
《JVM源码分析之Java对象的创建过程》一文中分析了Java对象创建的整个过程,代码实现如下:对象的初始化过程会对
has_finalizer_flag和
RegisterFinalizersAtInit进行判断,如果类重写了
finalize方法,且方法体不为空,则调用
register_finalizer函数,继续看
register_finalizer函数的实现:
其中
Universe::finalizer_register_method()缓存的是
jdk中
java.lang.ref.Finalizer类的
register方法,实现如下:
在jvm中通过
JavaCalls::call触发
register方法,将新建的对象
O封装成一个
Finalizer对象,并通过
add方法添加到
Finalizer链表头。对象
O和
Finalizer类的静态变量
unfinalized有联系,在发生GC时,会被判定为活跃对象,因此不会被回收
FinalizerThread线程
在Finalizer类的静态代码块中会创建一个
FinalizerThread类型的守护线程,但是这个线程的优先级比较低,意味着在cpu吃紧的时候可能会抢占不到资源执行。
FinalizerThread线程负责从
ReferenceQueue队列中获取
Finalizer对象,如果队列中没有元素,则通过
wait方法将该线程挂起,等待被唤醒
如果返回了
Finalizer对象,执行对象的
runFinalizer()方法,其实可以发现:在
runFinalizer()方法中主动捕获了异常,即使在执行
finalize方法抛出异常时,也没有关系。
通过
hasBeenFinalized方法判断该对象是否还在链表中,并将该
Finalizer对象从链表中删除,这样下次gc时就可以把原对象给回收掉了,最后调用了native方法
invokeFinalizeMethod,其中
invokeFinalizeMethod方法最终会找到并执行对象的
finalize方法。
ReferenceHandler线程
有个疑问:既然FinalizerThread线程是从
ReferenceQueue队列中获取
Finalizer对象,那么
Finalizer对象是在什么情况下才会被插入到
ReferenceQueue队列中?
Finalizer的祖父类
Reference中定义了
ReferenceHandler线程,实现如下:
当
pending被设置时,会调用
ReferenceQueue的
enqueue方法把
Finalizer对象插入到
ReferenceQueue队列中,接着通过
notifyAll方法唤醒
FinalizerThread线程执行后续逻辑,实现如下:
pending字段什么时候会被设置?在GC过程的引用处理阶段,通过
oopDesc::atomic_exchange_oop方法把发现的引用列表设置在
pending字段所在的地址
Finalizer导致的内存泄漏
平常使用的Socket通信,SocksSocketImpl的父类重写了
finalize方法
这么做主要是为了确保在用户忘记手动关闭
socket连接的情况下,在该对象被回收时能够自动关闭
socket来释放一些资源,但是在开发过程中,真的忘记手动调用了
close方法,那么这些
socket对象可能会因为
FinalizeThread线程迟迟没有执行到这些对象的
finalize方法,而导致一直占用某些资源,造成内存泄露。
相关文章推荐
- 深入分析Object.finalize方法的实现原理
- 深入分析Object.finalize方法的实现原理
- 深入分析 Java 方法反射的实现原理
- Object.finalize方法的实现原理
- 深入分析Java方法反射的实现原理
- 深入分析 Java 方法反射的实现原理
- 深入分析 Java 方法反射的实现原理
- 深入分析Java方法反射的实现原理
- 深入分析Java方法反射的实现原理
- 聊聊并发(一)——深入分析Volatile的实现原理
- 聊聊并发(一)——深入分析Volatile的实现原理
- java多线程-专题-聊聊并发(一)深入分析Volatile的实现原理
- js实现跨域的4种实用方法原理分析
- 深入分析Volatile的实现原理
- 深入分析基于VCL派生的ActiveX控件的实现原理及应用
- 聊聊并发(一)深入分析Volatile的实现原理
- 深入分析Volatile的实现原理,原子操作
- 深入分析MVC中通过IOC实现Controller依赖注入的原理
- 分析了一下JQuery中的extend方法实现原理
- 聊聊并发(一)——深入分析Volatile的实现原理