+ 设为首页 + 加入收藏

 
 
白起真的坑杀了四十万赵
百胜集团为什么要拆分中
EADICE游戏战地系列小队系
PHP的哪个MVC框架值得推荐
2019年现在的你为何还用黑
Java的finalizercleaner等如何实
     西安港汇实业有限公司

销售热线:张经理: 15191895022
     白经理: 18109296883
QQ:2355807252 2355807260
技术热线:15191895022
传真:029-86189022 4006388838转00685

 
当前位置:主页 > 资料下载 >
Java的finalizercleaner等如何实现
发布者:知乎 发布时间:2019-12-09 23:51:08 阅读:498次 
摘要:先看假设::的主流实现是基于的对的。现代主流的的基础算法都是从系的演化出来的。:并不对每个续个释放,而是(在一定的处理后)对一个的所有进
先看假设:0:JVMGC的主流实现是基于tracing的对的。现代主流JVM的GC的基础算法都是从tracing系的mark-sweep/mark-compact/copying演化出来的。1:tracing并不对每个unreachableObject续个释放,而是(在一定的处理后)对一个region的所有Object进行释放对的。TracingGC的效率的来源就是它有些耗时的阶段只跟活对象的状况相关,而死去的对象直接被这些阶段忽略(尤其是copyingGC,整个GC过程的开销都只跟活对象有关而跟死对象无关),所以如果等一段时间再batch起来处理的话,那些在这个时间段内死去了的对象就不会产生收集开销,就省去了像引用计数那样需要时刻记录对象图的局部变化来跟踪中间状态的开销。这样,只要能控制tracing系GC的触发频率低(意味着headroom要大),它的工作效率就可以非常高。2:所以,当内存足够大的时候,tracing系GC可能比stackallocation/手动free更快(见GarbageCollectionCanBeFasterThanStackAllocation)唔…现实地说tracingGC要比优化好的stackallocation快还是很困难的,或者说只能在很受限的场景有这种效果。如果headroom大的话,要比朴素的手动malloc/free快有可能,要在多线程条件下比朴素引用计数throughput更高那简直易如反掌。然后回答问题:0:Java为什么有finalizer(尽管不可靠)?只是作为lastlineofdefense,是一种保底的措施。由于GC只能管理自动内存资源而无法管理程序所需要的各种其它资源(例如GC堆外的nativememory、filehandle、socket、drawdevicehandle啥的),程序员必须要自己手动来管理这些资源。只是纯粹为了避免在对象死了之后它原本持有的这样的资源泄漏,Java才提供了finalizer机制到让用户注册finalize()这么个回调方法来定制GC清理对象的行为。确实Java语言规范里是说底层实现可以自由选择当对象可以被回收之后何时调用finalize();换句话说在无限远的未来才调用finalize()也是符合规范的,现实来说就是等价于永远不调用finalize()也是符合规范的。但靠谱的JVM实现都还是会在维持GC效率的前提下尽快对可以回收的对象去调用finalize()方法。1:有没有任何办法保证finalizer(或类似机制)在一定条件满足时(如GC被触发时)必会执行?现实上说是会被执行的,但没办法抽象地、严格地有什么机制去保证finalize()一定被调用。HotSpotVM实现finalizer的办法其实很直观:系统通过特殊的FinalReference(一种介于WeakReference和PhantomReference之间的内部实现的弱引用类型)来引用带有非空finalize()方法的对象——这些对象在创建的时候就会伴随创建出一个引用它的FinalReference出来。然后在GC的时候,FinalReference也跟其它弱引用类型一样由ReferenceProcessor发现并处理:GC的marking分为strongmarking和weakmarking两个阶段,在strongmarking过程中如果mark到弱引用的话,并不是立即把其referent也mark上,而是会把弱引用记录在ReferenceProcessor里对应的队列里。Strongmarking之后会做referenceprocessing,扫描前面记录下来的弱引用看它们的referent是否已经被strongmarking标记为活,如果是的话说明对象还活得好好的,就不管它了让它继续活下去,反之则意味着referent指向的对象只是weak-reachable,就要做相应的弱引用处理。对FinalReference来说,弱引用处理就是这次把referent还是标记为活的,并把它加入到finalizequeue里去等着被FinalizeThread去调用其finalize()方法。等它的finalize()方法被调用过之后,下次再GC的时候这个对象就没有FinalReference引用了,所以就不会再经历一次弱引用处理,就可以好好长眠了。那么finalizer会有啥问题呢?首先是会慢——GC在做referenceprocessing的时候常常是在stop-the-worldpause里做的,会增加GC暂停时间,而且后面跑finalizer也要占CPU;其次是finalizer还是有可能没能被调用上,会泄漏资源。举个简单的例子,HotSpotVM默认是在一个JVM实例内开一个FinalizeThread来专门去调用finalize()方法的。所有GC发现可以被回收但有finalizer的对象都会被挂在一个全局的finalizequeue上,然后这个FinalizeThread从queue里逐个取出对象来调用其finalize()方法。那么假如有个对象在自己的finalize()写了个无限循环会怎样?在默认配置下,finalizequeue里挂在这个对象之后的对象的finalize()方法就要在无限远的未来才能被调用到了——悲剧。JDK有提供一个标准API,System.runFinalization(),来让当前Java线程在处理完finalizequeue之前block住。这个API的描述也就是“尽力而为”,并不保证任何行为,但现实来说它是会等到finalizequeue真的空了才返回的。JDK8u里HotSpotVM的实现方法是调用java.lang.ref.Finalizer.runFinalization(),其中会在FinalizeThread之外再开一个SecondaryFinalizeThread来尝试加速处理finalizequeue。那么如果我们的finalizequeue上挂着两个调皮的对象都有无限循环,这就还是能把两个处理线程都卡住,于是queue里剩下的对象还是得到无限远的未来才能得到处理…顺带放俩传送门:RednaxelaFX:为什么Java有GC还需要自己来关闭某些资源?[Java]新版本的Java将会废弃Object.finalize(),并添加新的java.lang.ref.Cleaner2:GCCanbeFasterThanStackAllocation在finalizer下是否依然成立?Java程序要想性能好请尽量不要用finalize()嗯。看了上面的实现方式的描述,您觉得这还能比stackallocation快么?>_<(不过公平地说,C++对象的析构器里要是写了无限循环的话一样悲剧。我们也见过不少有趣的情况是析构器里的逻辑的开销非常大,但因为隐藏在代码里(“}”!),大家写代码的时候未必会一眼看出来,然后就要漫长地通过跑性能测试啊啥的才发现这问题了。这锅要让stackallocation背似乎不合理。同理的话,finalize开销大的锅让GC背似乎也不合理。Anyway这里锅让谁背就见仁见智啦)
相关文章
友情链接:
Copyright © 2010-2013 www.gongyezidonghua.com All Rights Reserved. 版权所有 西安港汇实业
地址:西安市未央区大明宫万达广场2号甲写1408 电话:029-86189022 传真:4006358835-00685
陕ICP备13005737号 网站地图