我有一个使用JNI调用Java代码的.NET应用程序。在.NET终结器上,我们调用JNI调用来清理Java上的连接资源。但这个JNI不时被卡住了。 正如预期的那样,所有.NET进程都停滞不前,而且从未发布过。
Bellow你可以看到我们从.NET获得的线程转储:
NET调用堆栈 功能
.JNIEnv_.NewByteArray(JNIEnv_*, Int32)
Bridge.NetToJava.JVMBridge.ExecutePBSCommand(Byte[], Int32, Byte[])
Bridge.Core.Internal.Pbs.Commands.PbsDispatcher.Execute(Bridge.Core.Internal.Pbs.PbsOutputStream, Bridge.Core.Internal.DispatcherObjectProxy)
Bridge.Core.Internal.Pbs.Commands.PbsCommandsBundle.ExecuteGenericDestructCommand(Byte, Int64, Boolean)
Bridge.Core.Internal.DispatcherObjectProxy.Dispose(Boolean)
Bridge.Core.Internal.Transaction.Dispose(Boolean)
Bridge.Core.Internal.DispatcherObjectProxy.Finalize()
完整的通话栈 功能
ntdll!KiFastSystemCallRet
ntdll!NtWaitForSingleObject+c
kernel32!WaitForSingleObjectEx+ac
kernel32!WaitForSingleObject+12
jvm!JVM_FindSignal+5cc49
jvm!JVM_FindSignal+4d0be
jvm!JVM_FindSignal+4d5fa
jvm!JVM_FindSignal+beb8e
jvm+115b
jvm!JNI_GetCreatedJavaVMs+1d26
Bridge_NetToJava+1220
clr!MethodTable::SetObjCreateDelegate+bd
clr!MethodTable::CallFinalizer+ca
clr!SVR::CallFinalizer+a7
clr!WKS::GCHeap::TraceGCSegments+239
clr!WKS::GCHeap::TraceGCSegments+415
clr!WKS::GCHeap::FinalizerThreadWorker+cd
clr!Thread::DoExtraWorkForFinalizer+114
clr!Thread::ShouldChangeAbortToUnload+101
clr!Thread::ShouldChangeAbortToUnload+399
clr!ManagedThreadBase_NoADTransition+35
clr!ManagedThreadBase::FinalizerBase+f
clr!WKS::GCHeap::FinalizerThreadStart+10c
clr!Thread::intermediateThreadProc+4b
kernel32!BaseThreadStart+34
答案 0 :(得分:2)
我不知道.NET终结器对于Java终结器是否同样糟糕,但使用可能(死)锁定代码(我在最底层看到Win32条件调用)来自终结器(无论平台)是什么绝对是个坏主意。您需要清除任何潜在锁定的本机代码,或者在.NET级别紧急制动超时
答案 1 :(得分:1)
由于我没有找到问题,所以我不会在这里发表正式答案,而是讲一个有时我经历过类似事情的故事:
我们通过JNI创建了由java对象支持的C ojects,我们决定在finalize方法中清理C对象。但是,我们设想了死锁,因为finalize是从非应用程序线程(垃圾收集器)调用的。由于整个wolrd在收集垃圾时停止,每当终结器遇到锁定时,它立即就会死锁。因此我们决定使用一种名为幻像引用的java机制。可以将数字绑定到这些“引用”(C指针)中的每一个,然后VM删除它将这样的引用放入队列的引用对象。并且可以在适当的时候提取此数据并删除C对象。
我认为至少你的问题是一样的。