3

I have a .NET application that is using JNI to call Java code. On the .NET finalizer we call a JNI call to clean the connected resource on Java. But from time to time this JNI gets stuck. This as expected stuck the all .NET process and never releases.

Bellow you can see the thread dump we got from .NET:

NET Call Stack Function

.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() 

Full Call Stack Function

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
4

2 回答 2

2

I have no idea whether .NET finalizers are equally bad idea to Java finalizers, but using a potentially (dead)locking code (i see Win32 condition call at the very bottom) from anything like finalizer (regardless of the platform) is definitely a bad idea. You need to clean your native code of any potential locking, or have an emergency brake timeout at the level of .NET

于 2012-08-15T15:31:24.127 回答
1

As I didn't find a question I won't post a formal answer here but rather tell a story about something similar I underwent sometimes:

We created C ojects via JNI, that were backed by java object, and we decided to clean the C objects within the finalize method. However, we envisioned deadlocks, as the finalize is called from a non-application thread, the garbage-collector. As the entire wolrd is stopped while collecting the garbage, whenever the finalizer meets a lock it's immediately a dead lock. Thus we decided to use a java mechnism called phantom references. It's possible to bind a number to each of these 'references' (the C pointer) and then the VM removes an referenced object it puts such an reference into a queue. And one can pull this data whenever appropriate and remove the C object.

I think at least your problem is the same.

于 2012-08-15T15:27:30.057 回答