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?

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

时间: 2024-11-05 18:39:29

Android开发经验—不要指望类的finalize方法干你想要干的活的相关文章

Java类的finalize()方法

Java的Object类提供了一个finalize()方法,签名如下: protected void finalize() throws Throwable { } 该方法在JVM进行垃圾回收时之行,所以任何类都可以Override该方法,来让自己的类的实例在被回收之前,执行一系列动作. 可以通过如下两种方式来让主动让JVM进行垃圾回收: System.gc(); Runtime.getRuntime().gc(): 但是JVM不保证立即执行gc操作. finalize()方法使用示例如下: p

Android app启动activity并调用onCreate()方法时都默默地干了什么?

Android app启动activity并调用onCreate() 方法时都默默地干了什么? 在AndroidManifest.xml文件中的<intent-filter>元素中有这么两句: <intent-filter>     <action android:name="android.intent.action.MAIN"/>     <category android:name="android.intent.categor

Android开发实用工具类(小方法)

1,邮箱地址只展示部分,只展示@前面部分的第1个及最后一个字符,其它的用*代替: public static String spliteEmail(String email) {/**传入邮箱地址*/ String newEmail = email.split("@")[0];/**获取到邮箱@前面部分*/ String[] mails = new String[newEmail.length()]; StringBuffer sb = new StringBuffer(); if (

详解java垃圾回收机制(转)及finalize方法(转)

详细介绍Java垃圾回收机制 垃圾收集GC(Garbage Collection)是Java语言的核心技术之一,之前我们曾专门探讨过Java 7新增的垃圾回收器G1的新特性,但在JVM的内部运行机制上看,Java的垃圾回收原理与机制并未改变.垃圾收集的目的在于清除不再使用的对象.GC通过确定对象是否被活动对象引用来确定是否收集该对象.GC首先要判断该对象是否是时候可以收集.两种常用的方法是引用计数和对象引用遍历. 引用计数收集器 引用计数是垃圾收集器中的早期策略.在这种方法中,堆中每个对象(不是

[java]final关键字、finally关键字与finalize()方法

final关键字: final关键字通常指的是“无法改变的”,使用“无法改变”这样修饰可能出于两个原因:设计或者效率. final可以修饰变量.方法和类. 一.final变量 一个既是static又是final的域只占据一段不能改变的存储空间. 当对对象引用而不是基本类型运用final修饰时,其含义会有一点迷惑.对于基本类型,final使数值恒定不变.而用于对象引用,final使引用恒定不变.一旦引用被初始化指向一个对象,就无法再把它改为指向另一个对象.然而,对象自身却是可以修改的,java并未

finalize方法与Java GC

转自http://www.threaddeath.com/ 闲逛ITEye时看到了译帝的一篇翻译博客,其中提到了关于Java类重写finalize方法后带来的诡异的GC overhead limit问题.博客的结尾非常详细的说明了这个问题产生的原理,但是始终有一个地方没有得到清晰的答案:由于finalize方法是Object类的protected方法,即无论重写与否,所有的Java类都会带有finalize方法,但为什么只有重写之后才会出现GC问题,不重写与重写的真实差别到底在哪儿? 通过思考始

【翻译】finalize方法到底要干嘛

以下是JDK中的描述: Called by the garbage collector on an object when garbage collection determines that there are no more references to the object. A subclass overrides the finalize method to dispose of system resources or to perform other cleanup. 当垃圾回收器发现

[ 转载 ] Java基础10--关于Object类下所有方法的简单解析

关于Object类下所有方法的简单解析 类Object是类层次结构的根类,是每一个类的父类,所有的对象包括数组,String,Integer等包装类,所以了解Object是很有必要的,话不多说,我们直接来看jdk的源码,开始我们的分析之路 1.hashcode() public native int hashCode();//native说明跟机器有关,跟对象的地址有关 如果我们新建一个类,而hashcode没有被重写的话,那么hashcode返回的值只于对象的地址有关,如果hashcode被重

巩固 finalize() 方法

1.java gc要回收对象的时候,首先要调用这个类的finalize方法,但是并不是调用这个finalize方法就等同于垃圾回收,只是在gc之前 finalize 方法会被调用,所以基本可以说其被回收了. 2.但由于gc的自动回收机制,并不能保证 finalize 方法会被及时地执行(垃圾对象的回收时机具有不确定性),也不能保证它们会被执行(程序由始至终都未触发垃圾回收). 3.提供这样的机制的原因在于:让我们有时想在撤消一个对象时完成一些操作(有点像生命周期钩子),比如一些Java以外的代码