当前位置: 代码迷 >> Android >> Android开发心得—不要指望类的finalize方法干你想要干的活
  详细解决方案

Android开发心得—不要指望类的finalize方法干你想要干的活

热度:34   发布时间:2016-04-28 04:45:58.0
Android开发经验—不要指望类的finalize方法干你想要干的活

       之所以专门写一篇关于finalize方法的博客,是因为被这个方法坑过,在写一个读取jni数据类的时候,我在类的finalize方法中调用了关闭文件和释放内存的方法,结果导致在频繁调用这个类的时候在JNI里面报异常,类本来就是单例的,按理分析不应该存在这样的情况,到最后分析出来就是因为在该类的finalize方法中调用了关闭文件的方法,导致下次进入再次打开文件时,被系统调用finalize方法给关闭掉了,出现异常的代码如下。

public class TraceHandle{    static{        try{            System.loadLibrary("TraceHandle");        }catch (UnsatisfiedLinkError ule){            Log.e("JNI", "WARNING: Could not load TraceHandle.so");        }    }    private TraceHandle( String filePath ){        mFilePath = filePath;        open( filePath );    }    /**     * 实例化TraceHandle     *      * */    public static TraceHandle create( String filePath ){        if (null == mTraceHandle){            mTraceHandle = new TraceHandle( filePath);        }        mTraceHandle.mInitCount++;        return mTraceHandle;    }    /**     * 退出时销毁TraceHandle     *      * @return null.     */    public TraceHandle destory( ){        mInitCount--;        if (mInitCount == 0 && mTraceHandle != null){            mTraceHandle.close();            mTraceHandle = null;        }        return null;    }    private void celan(){        if (mTraceHandle != null){            mTraceHandle.close();            mTraceHandle = null;        }    }    @Override    protected void finalize() throws Throwable{        super.finalize();        //这是被系统调用的方法,系统会根据系统环境来调用,对于程序来说它的调用实际不可预见        celan();    }        // 1、打开文件    private native int open(String tracePath );    // 2、搜索指定汉字    private native int[] search(byte[] wordArray);    // 3、必须关闭文件    private native boolean close();        private int mInitCount = 0;    private String mFilePath = null;    private static TraceHandle mTraceHandle = null;}
     

        经过查阅资料和阅读《JAVA核心技术》里面相关的章节后,问题终于搞定。在《JAVA核心技术》一书中是这样描述finalize方法的:

       “可以为任何一个类添加finalize方法。finalize方法将在垃圾回收器清除对象之前调用。在实际应用中,不要依赖于使用finalize方法回收任何短缺的资源,这是因为很难知道这个方法什么时候才能够调用。

       如果某个资源需要在使用完毕立刻被关闭,那么就需要由人工来管理。可以应用一个类似dispose或close的放来完成相应的清理操作。特别需要说明,如果一个类使用了这样的方法,当对象不再被使用时一定要调用它。”

修改后的代码如下,去掉了finalize方法:

public class TraceHandle{    static{        try{            System.loadLibrary("TraceHandle");        }catch (UnsatisfiedLinkError ule){            Log.e("JNI", "WARNING: Could not load TraceHandle.so");        }    }    private TraceHandle( String filePath ){        mFilePath = filePath;        open( filePath );    }    /**     * 实例化TraceHandle     *      * */    public static TraceHandle create( String filePath ){        if (null == mTraceHandle){            mTraceHandle = new TraceHandle( filePath);        }        mTraceHandle.mInitCount++;        return mTraceHandle;    }    /**     * 退出时销毁TraceHandle     *      * @return null.     */    public TraceHandle destory( ){        mInitCount--;        if (mInitCount == 0 && mTraceHandle != null){            mTraceHandle.close();            mTraceHandle = null;        }        return null;    }    private void celan(){        if (mTraceHandle != null){            mTraceHandle.close();            mTraceHandle = null;        }    }    // 1、打开文件    private native int open(String tracePath );    // 2、搜索指定汉字    private native int[] search(byte[] wordArray);    // 3、必须关闭文件    private native boolean close();        private int mInitCount = 0;    private String mFilePath = null;    private static TraceHandle mTraceHandle = null;}

       由于java有自己的垃圾回收机制,所以在写代码的时候千万不能依赖于它的一些方法来回收资源(比如finalize,gc),因为这些方法的调用时机都是不可预知的。

参考资料:

1、Why not to use finalize() method in java

2、When is the finalize() method called in Java?


  相关解决方案