美文网首页Android开发学习
Android中的TimeoutExceptions

Android中的TimeoutExceptions

作者: joyousx | 来源:发表于2016-12-21 22:01 被阅读7770次

    翻译:
    http://stackoverflow.com/questions/24021609/how-to-handle-java-util-concurrent-timeoutexception-android-os-binderproxy-fin

    有时会遇到以下崩溃:

    The error is a variation of: "com.android.internal.BinderInternal$GcWatcher.finalize() timed out after 10 seconds"
    
    java.util.concurrent.TimeoutException: android.os.BinderProxy.finalize() timed out after 10 seconds
    at android.os.BinderProxy.destroy(Native Method)
    at android.os.BinderProxy.finalize(Binder.java:459)
    at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:187)
    at java.lang.Daemons$FinalizerDaemon.run(Daemons.java:170)
    at java.lang.Thread.run(Thread.java:841)
    

    它其实是发生在 GcWatcher.finalize, BinderProxy.finalize 和 PlainSocketImpl.finalize 中的一类TimeoutExceptions。这个异常90%都是发生在4.3、4.4的android系统上。

    这个问题的根源在于设备会'Goes to Sleep'一会儿,就是说操作系统会通过熄屏、降低cpu循环等方式降低电量消耗,进入休眠状态。它是通过在内核层暂停进程的方式来实现的。这可能发生在常规app运行的过程中, 但是会停在一次内核调用上,比如内核层的上下文切换。这就是Dalvik GC参与最初所说TimeoutExceptions问题的方式。

    Dalvik GC的基本工作方式就是,在GC循环中将收集到的一系列的对象去销毁,其主要流程可以描述为:

    • take starting_timestamp,
    • remove object for list of objects to release,
    • release object - finalize() and call native destroy() if required,
    • take end_timestamp,
    • calculate (end_timestamp - starting_timestamp) and compare against a hard coded timeout value of 10 seconds,
    • if timeout has reached - throw the concurrent.TimeoutException
      and kill the process.

    现在思考下接下来的这个场景:
    有一个后台运行的进程,在运行过程中,对象被创建、使用以及被收集(以释放内存)。一般的,应用不会使用Wakelock,因为会很耗电并且也没必要,这意味着应用会不时的执行GC动作。通常情况下,GC动作会正常的执行完成而不会被挂起。但是,有些时候(很稀少),操作系统会在GC动作的过程中进入休眠。如果你的应用运行时间足够长,它就有可能发生。现在,想一下GC循环中的有关时间戳的逻辑:有可能发生,设备开始进行GC,并且在处理系统对象销毁(native层的destroy())的过程中进入休眠, 然后被唤醒,恢复运行,记录现在的时间戳,也就是说这次GC动作花费的时间=销毁动作执行时长+休眠时长。如果休眠时间超过10s, 就会抛出concurrent.timeout异常。

    这个问题不能完全避免,只要你的应用在后台运行。我们可以通过调用wakelock减少设备休眠,但这个方法会引来一系列问题。最靠谱的方法还是,** 尽量减少GC动作的被调用次数 **,使得这个场景少出现。

    另外,在Android5.0+系统上,因为使用了ART GC,使得这个崩溃的发生机率大大降低了。
    目前Android project增加了大量的关于'GC是如何(在ART上)工作' 的之类的文档,感兴趣的话,可以看看:https://source.android.com/devices/tech/dalvik/gc-debug.html

    相关文章

      网友评论

      • 不可复制_4612:https://stackoverflow.com/questions/24021609/how-to-handle-java-util-concurrent-timeoutexception-android-os-binderproxy-fin
        可以试下下这个下面的解决方法
        public static void fix() {
        try {
        Class clazz = Class.forName("java.lang.Daemons$FinalizerWatchdogDaemon");

        Method method = clazz.getSuperclass().getDeclaredMethod("stop");
        method.setAccessible(true);

        Field field = clazz.getDeclaredField("INSTANCE");
        field.setAccessible(true);

        method.invoke(field.get(null));

        }
        catch (Throwable e) {
        e.printStackTrace();
        }
        }
        在 Application 的attatchBaseContext()调用就行了
        由于遇到的大部分是oppo机型出现的问题,所以我只针对oppo处理
      • 不可复制_4612:在bugly上报此类异常的机型中,OPPO的最多,这也和该厂家激进的内存限制策略有关系吧,为了保证系统流畅就疯狂杀内存。。。。
        Hawozhencai:一样的bug,红米2a
        7d2822b9c9cb:我也遇到这个问题了,也是OPPO的机器
        墨洵MOXUN:我这边收集到的一个bug还真是oppo的
      • 非墨Zero:你把watchdog那个线程关了就好了~
        不可复制_4612:@W_W_ 参见5楼
        W_W_:怎么个关闭法?
      • 小小亭长:也就是需要供应商配合来解决这个问题啦?

      本文标题:Android中的TimeoutExceptions

      本文链接:https://www.haomeiwen.com/subject/vglvmttx.html