我在Android应用程序中遇到了一个非常奇怪的问题.在某个点之后(主要活动开始并且显示片段的时候),FinalizerDaemon会停止处理对象并且垃圾堆积不断.看一下线程转储,它似乎停留在ReferenceQueue.remove()
:
"FinalizerDaemon@4461" daemon prio=5 waiting
java.lang.Thread.State: WAITING
at java.lang.Object.wait(Object.java:-1)
at java.lang.Object.wait(Object.java:423)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:101)
- locked <0x1173> (a java.lang.ref.ReferenceQueue)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:72)
at java.lang.Daemons$FinalizerDaemon.run(Daemons.java:185)
at java.lang.Thread.run(Thread.java:818)
Run Code Online (Sandbox Code Playgroud)
但队列并非空.如果我在使用app一段时间之后转储堆,那么队列实际上是数千个条目.数据结构也看起来不破:
在分配和垃圾收集后再次转储更多显示队列的头部与以前相同的Matrix实例.
现在,我注意到了这一点,因为我保留了一些C++对象,需要在某些时候释放它们.虽然我怀疑终结器调用JNI函数并在C++端做一些愚蠢的操作可能会以某种方式破坏它,但我的所有日志都表明所有终结器都运行良好并返回而不会抛出任何东西,直到它们随机停止被调用.此外,最终的调用不应该打破守护进程,除了整个应用程序或其他东西,因为看门狗应该处理运行时间太长并抛出异常的终结器.
我尝试了一个显式的System.runFinalization()
,它所做的只是永远挂起主线程,等待从未运行的守护进程.
知道怎么会这样吗?
我偶然发现了一个非常奇怪的问题,我无法理解任何问题.首先是一些背景故事:
我正在尝试运行JavaScriptCore并将其用作Android应用程序的各种脚本语言.麻烦的是,主要线程上的堆栈大小在较旧的Android版本上非常有限(类似于API 16上的12k).但是,我仍然希望在主线程上调用JS,让它回调请求事情并使所有这些看起来都是同步的.没问题 - 我会甩掉几个通道... khm ... SynchronousQueues并反复弹跳执行.这是我的代码的样子.
它非常简单 - 每次调用延迟时 - 它会反弹到另一个线程并从那里继续.唯一的问题是,它不起作用.在执行Javascript代码的实际用例中,它在某些时候非常可靠地失败,尽管对于模拟器和不同的设备而言并不是在同一个位置.Logcat总是看起来非常无害:
I/JavaScriptCore: Lockstep [Main]: Defer
I/JavaScriptCore: Lockstep [Main]: Send EXECUTE_FUNC
I/JavaScriptCore: Lockstep [Background]: Receive EXECUTE_FUNC
I/JavaScriptCore: Lockstep [Background]: Defer
I/JavaScriptCore: Lockstep [Background]: Send EXECUTE_FUNC
Run Code Online (Sandbox Code Playgroud)
然而,第二次EXECUTE永远不会被主要接收,即使看跌.据我所知,对于同步队列来说甚至都不可能.查看线程转储,后台线程正在运行循环中等待下一条消息,而main正在停靠在incoming.take上.没有其他线程与此交互.
在我的一个设备上,我可以设置一个条件断点,以确保它停止工作的确切时刻,我可以暂停它,就像MAIN正在等待那个EXECUTE消息一样.消息是非空的,此时的foregroundQueue正在工作,我可以使用或不使用Android Studio的超时轮询它,取其大小,无论如何.我一踏完所有操作就挂了.
当然,我怀疑是JNI恶作剧,但在Logcat中没有内存转储,分段错误或任何警告.
此外,它不仅仅是采取 - 即使我做了一个非常肮脏的繁忙等待:
Message msg = incoming.poll();
if(msg == null) {
Thread.sleep(20);
continue;
}
Run Code Online (Sandbox Code Playgroud)
Main停留在轮询上,后台线程每隔20毫秒就会快速地在另一个队列中忙碌起来.
我尝试使用一个非常懒惰的因子嵌套延迟,这个因子喜欢睡眠很多而且没有问题,尽管有200个深度,整数溢出:
LockstepThread t = new LockstepThread();
int deferredFactoriel(final int n) {
if(n == 0) {
return 1;
}
return n * t.defer(new Functor<Integer>() { …
Run Code Online (Sandbox Code Playgroud)