HotSpot SA(三):FinalizerInfo

前面我们已经把玩过SA工具中的JStack和ClassDump,今天再来看个好玩的,FinalizerInfo。

Object#finalize

看名字多半能猜到,FinalizerInfo是跟Object的的执行有关的,

Called by the garbage collector on an object when garbage collection determines that there are no more references to the object.

然后我翻了好久的官方文档才找到这篇Troubleshooting Guide for HotSpot VM中的有对finalize相关实现的描述 ,

One other potential source of OutOfMemoryError arises with applications that make excessive use of finalizers. If a class has a finalize method, then objects of that type do not have their space reclaimed at garbage collection time. Instead, after garbage collection the objects are queued for finalization, which occurs at a later time. In the Sun implementation, finalizers are executed by a daemon thread that services the finalization queue. If the finalizer thread cannot keep up with the finalization queue, then the Java heap could fill up and OutOfMemoryError would be thrown.

也就是说,在对象被回收之前,需要执行finalize方法,而finalize方法的执行又是需要排着队由某个线程来一个个消费的。下面我们通过会阻塞住的finalize方法来验证看看,

{() throws Throwable {System.out.println(“finalize#” + this);super.finalize();System.in.read(); // 这个finalize方法将会卡住}}{() throws Throwable {System.out.println(“finalize#” + this);super.finalize();System.in.read(); // 这个finalize方法也会卡住}}(String[] args) throws Exception{foo();bar();System.gc();Thread.sleep(2000);System.in.read();}private static Foo foo() {return new Foo();}private static Bar bar() {return new Bar();}

如果上述没错,那么Foo跟Bar只要其中一个的finalize方法执行了,另一个必定得不到执行,因为单个队列,有一个卡住了那么其后续的必然也无法被消费了。 事实确实如此,输出只有一行finalize#me.kisimple.just4fun.Main$Bar@571688,所以Foo必定是在等待着被finalize。这时候FinalizerInfo就派上用场了,用它我们可以观察VM中有哪些正在等待被finalize的对象,

# java7 sun.jvm.hotspot.tools.FinalizerInfo 5960Attaching to process ID 5960, please wait…Debugger attached successfully.Server compiler detected.JVM version is 24.65-b04Number of objects pending for finalization: 33Count Class description——————————————————-$ZipFileInputStream$ZipFileInflaterInputStreamme.kisimple.just4fun.Main$Foo

妥妥的我们看到了1 me.kisimple.just4fun.Main$Foo,验证了文档中的描述。

FinalizerThread

更进一步,我们可以冲进FinalizerInfo的源码看看,

/** The implementation here has a dependency on the implementation of* java.lang.ref.Finalizer. If the Finalizer implementation changes it’s* possible this method will require changes too. We looked into using* ObjectReader to deserialize the objects from the target VM but as* there aren’t any public methods to traverse the queue it means using* reflection which will also tie us to the implementation.** The assumption here is that Finalizer.queue is the ReferenceQueue* with the objects awaiting finalization. The ReferenceQueue queueLength* is the number of objects in the queue, and ‘head’ is the head of the* queue.*/

注释就已经告诉我们,存放等待finalize的对象的队列就是在。然后去看看Finalizer的源码,可以看到消费这个queue的线程,也就是线程,

() {if (running)return;(!VM.isBooted()) {// delay until VM completes initializationtry {VM.awaitBooted();} catch (InterruptedException x) {// ignore and continue}}final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();running = true;for (;;) {try {Finalizer f = (Finalizer)queue.remove();f.runFinalizer(jla);} catch (InterruptedException x) {// ignore and continue}}} (JavaLangAccess jla) {synchronized (this) {if (hasBeenFinalized()) return;remove();}try {Object finalizee = this.get();if (finalizee != null && !(finalizee instanceof java.lang.Enum)) {///////////////////////////////////////////////// 最后由JavaLangAccess来真正执行Object#finalize了jla.invokeFinalize(finalizee);/* Clear stack slot containing this variable, to decreasethe chances of false retention with a conservative GC */finalizee = null;}} catch (Throwable x) { }super.clear();}

还有另一个方法,我们可以在FinalizerThread打断点进行调试,,这样也是能验证我们的想法的。alright,今天就先到这吧^_^

参考资料

在乎的是看风景的心情,旅行不会因为美丽的风景终止。

HotSpot SA(三):FinalizerInfo

相关文章:

你感兴趣的文章:

标签云: