Android踩坑经验-Finalize TimeoutException原因及解决方案

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/longlong2015/article/details/88826234

调用栈信息:
在这里插入图片描述
背景知识:FinalizerDamemon和FinalizerWatchdogDaemon
FinalizerDamemon
析构守护线程,重写了finalize的对象,在创建时会新建一个FinalizerReference,这个对象是强引用类型,封装了override finalize()的对象,下面直接叫原对象。原对象没有被其他对象引用时(FinalizeReference除外),执行GC不会马上被清除掉,而是放入一个静态链表中(ReferenceQueue),析构守护线程获得时间片后,弹出链表对象,并执行原对象finalize()方法,对应的FinalizerReference对象在下次执行GC时就会被清理掉。
FinalizerWatchdogDaemon
当一个实例的finalize函数,花费超过MAX_FINALIZATION_MILLIS(默认10s,很多第三方厂商改为60s),则FinalizerWatchdogDaemon线程会让VM退出,应用程序程序crash
原因:
1:Finalize对象累积太多,导致FinalizerDaemon线程来不及处理
Q:项目中没有类重写finalize方法,什么对象累积太多?
可能项目中没有类重写finalize方法,但Android系统中有非常多的类实现了finalize方法,如:Binder,View,Matrix,Bitmap,AssetManager等
2:运行过程中息屏,或者某些省电模式下,系统CPU降频,FinalizerDaemon线程获得时间片短且执行速度慢导致超时
3:某个析构函数调用阻塞
解决方法:
这个问题,并不像NPE那样,可以快速定位解决,甚至来说,这个问题几乎无解。但可以通过反射调用让FinalizerWatchdogDaemon停止工作,从而让这种crash消除掉。
(现在Android版本不断升级,P以上对反射使用有限制,因此无法通过反射停止FinalizerWatchdogDaemon线程,但Android P的机器目前都是高端机,性能较好的机器出现此问题的概率本身就比较小,因此基本能解决finalize timeout问题)
参考代码:

        try {
            final Class clazz = Class.forName("java.lang.Daemon$FinalizerWatchdogDaemon");
            final Field field = clazz.getDeclaredField("INSTANCE");
            field.setAccessible(true);
            final Object watch = field.get(null);
            try {
                final Field thread = clazz.getSuperclass().getDeclaredField("Thread");
                thread.setAccessible(true);
                thread.set(watch,null);
            } catch (final Throwable t) {
                Log.e(TAG, "stopWatchDog: set null error" + t);
                t.printStackTrace();
                try {
                    final Method method = clazz.getSuperclass().getDeclaredMethod("stop");
                    method.setAccessible(true);
                    method.invoke(watch);
                } catch (final Throwable e) {
                    Log.e(TAG, "stopWatchDog: stop error" + t);
                    t.printStackTrace();
                }
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

还有一些理论上可能有帮助的措施:
1:减少内存占用,避免不必要的对象创建
2:消除内存泄露问题,缓解GC压力

展开阅读全文

没有更多推荐了,返回首页