.NET GC停留在终结器()的JNI调用上

时间:2012-08-15 14:52:05

标签: java .net java-native-interface clr

我有一个使用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

2 个答案:

答案 0 :(得分:2)

我不知道.NET终结器对于Java终结器是否同样糟糕,但使用可能(死)锁定代码(我在最底层看到Win32条件调用)来自终结器(无论平台)是什么绝对是个坏主意。您需要清除任何潜在锁定的本机代码,或者在.NET级别紧急制动超时

答案 1 :(得分:1)

由于我没有找到问题,所以我不会在这里发表正式答案,而是讲一个有时我经历过类似事情的故事:

我们通过JNI创建了由java对象支持的C ojects,我们决定在finalize方法中清理C对象。但是,我们设想了死锁,因为finalize是从非应用程序线程(垃圾收集器)调用的。由于整个wolrd在收集垃圾时停止,每当终结器遇到锁定时,它立即就会死锁。因此我们决定使用一种名为幻像引用的java机制。可以将数字绑定到这些“引用”(C指针)中的每一个,然后VM删除它将这样的引用放入队列的引用对象。并且可以在适当的时候提取此数据并删除C对象。

我认为至少你的问题是一样的。