HotSpot SA #3:FinalizerInfo

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

Object#finalize

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

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方法来验证看看,

    private static class Foo {
        @Override
        protected void finalize() throws Throwable {
            System.out.println("finalize#" + this);
            super.finalize();
            System.in.read(); // 这个finalize方法将会卡住
        }
    }

    private static class Bar {
        @Override
        protected void finalize() throws Throwable {
            System.out.println("finalize#" + this);
            super.finalize();
            System.in.read(); // 这个finalize方法也会卡住
        }
    }

    public static void main(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 5960
Attaching to process ID 5960, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.65-b04
Number of objects pending for finalization: 33

Count   Class description
-------------------------------------------------------
17  java.util.zip.ZipFile$ZipFileInputStream
11  java.util.zip.ZipFile$ZipFileInflaterInputStream
4   java.io.FileInputStream
1   me.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的对象的队列就是在java.lang.ref.Finalizer.queue。然后去看看Finalizer的源码,可以看到消费这个queue的线程,也就是Finalizer.FinalizerThread线程,

        public void run() {
            if (running)
                return;

            // Finalizer thread starts before System.initializeSystemClass
            // is called.  Wait until JavaLangAccess is available
            while (!VM.isBooted()) {
                // delay until VM completes initialization
                try {
                    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
                }
            }
        }
   private void runFinalizer(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 decrease
                   the chances of false retention with a conservative GC */
                finalizee = null;
            }
        } catch (Throwable x) { }
        super.clear();
    }

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

参考资料

时间: 2025-01-30 06:05:57

HotSpot SA #3:FinalizerInfo的相关文章

HotSpot SA #2:ClassDump

今天继续介绍HotSpot SA中的另一个好玩的工具,ClassDump.ClassDump可以在运行时dump类文件,我们可以用来dump一些动态生成或者运行时被修改了字节码的类.下面就借助ClassDump来看一看动态代理跟反射机制在运行时偷偷干的一些事情. 动态代理 看下面的栗子先, public interface Foo { void bar(); } public class FooImpl implements Foo { @Override public void bar() {

HotSpot SA #4:输出类加载路径

参考R大的文章,也写了一个SA的小工具,可以输出指定类(使用-Dme.kisimple.just4fun.ClassPathDump=类名指定)是从什么地方加载进来的, package me.kisimple.just4fun; import sun.jvm.hotspot.oops.*; import sun.jvm.hotspot.runtime.VM; import sun.jvm.hotspot.tools.Tool; public class ClassPathDump extends

金山剑侠情缘女主角阿SA称:最大武器是美色

9月10日消息,<剑侠情缘-藏剑山庄>开拍近2月,谢霆锋.蔡卓妍等出席了有金山组织的媒体见面.扮演唐门大小姐的阿SA说,"我在游戏中最大武器是美色." 在<剑侠情缘-藏剑山庄>中,饰演赵晓赵的谢霆锋谈到他对游戏的看法时表示,"生活.爱情.游戏缺一不可,并称不会阻止儿子卢卡斯玩游戏." 谢霆锋 扮演女主角的阿SA在回答她最擅长的武功时,她语出惊人的说道,"我在游戏最大的武器是美色". 阿SA[page] 据了解,<剑侠

阿Sa带男友正式见家长:爸爸非常支持我(图)

阿sa和陈伟霆阿sa阿sa爸爸 中新网10月15日电 阿Sa(蔡卓妍)与陈伟霆的热恋惹来不少流言蜚语.继日前两人被指其实各自背叛另一半,暗中交往一年,昨日又有杂志指陈伟霆为傍上身家半亿的阿Sa,早前暗中改动昔日与旧女友Angelababy的情侣十字架纹身,更加上"S"字,寓意跟阿Sa永远甜蜜.不过阿Sa并未受到传闻影响,开心承认已带男友正式见了家长. 据香港"明报"消息,阿Sa日前接受访问时透露,她早已跟陈伟霆约法三章,拒看所有报章杂志,抱着"活在当下,不

深入理解Java虚拟机:OutOfMemory实战

在Java虚拟机规范的描述中,除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生OutOfMemoryError(下文称OOM)异常的可能,本节将通过若干实例来验证异常发生的场景.并且会初步介绍几个与内存相关的最基本的虚拟机参数. 本节内容的目的有两个:第一,通过代码验证Java虚拟机规范中描述的各个运行时区域存储的内容:第二,希望读者在工作中遇到实际的内存溢出异常时,能根据异常的信息快速判断是哪个区的内存溢出,知道什么样的代码可能导致这些区域内存溢出,以及出现这些异常后该如何处理. 下文

IPSec两种模式:隧道模式和传输模式

IP_SECURITY协议(IPSec),是INTERNET工程任务组(IETF)为IP安全推荐的一个协议.通过相应的隧道技术,可实现VPN.IPSec有两种模式:隧道模式和传输模式.&http://www.aliyun.com/zixun/aggregation/37954.html">nbsp;    IPSec协议组还包括支持网络层安全性密钥管理要求的密码技术.ISAKMP(InternetSecurityAssociationKeyManagementProtocolInt

Sybase数据库sa密码丢失后解决方法_数据库其它

1.在Sybase目录的install子目录的启动server文件  RUN_server(这里的server表示你的服务器名称,如这里我的是RUN_FENGLB)名,编辑该文件,  在其中的"\data\master.dat -sFENGLB"后加入参数 -psa,保存该文件.  2.如果服务器已经启动,先停止之.  3.启动一个DOS窗口,转到上面的install目录,将DOS窗口的属性的屏幕缓冲区大小设置为9999,将执行第1步批处理文件以启动server,在启动之后,将DOS窗

SQL2000中的默认sa帐号的修改与删除方法_MsSql

现在用MSSQL的地方太多了,有很多做技术的个人电脑上也安装SQL专业版,因为它用的多,但用的人都知道,SQL有个超级用户sa,此用户默认情况下,它指派给固定服务器角色 sysadmin,并不能进行更改.一般懂点安全问题的技术人员都会把这个密码修改掉,但修改再复杂的密码都不是绝对安全的,一些暴力破解软件,菜鸟都会用.那怎么办呢,最好的办法就是删除或改名,下面提供方法. 为了加强安全把默认的sa用户更改掉,安全性会有大幅提升. Alter LOGIN sa DISABLE Alter LOGIN

SQL error: cannot use the special principal &#039;sa&#039;

 SQL error: cannot use the special principal 'sa' 解决方案: use dbname EXEC sp_changedbowner 'dbname' 参考:https://msdn.microsoft.com/en-us/library/ms178630.aspx