3

JNI を使用して Java コードを呼び出す .NET アプリケーションがあります。.NET ファイナライザーでは、JNI 呼び出しを呼び出して、Java 上の接続されたリソースを消去します。しかし、時々、この JNI が動かなくなることがあります。これは予想どおり、すべての .NET プロセスをスタックさせ、解放されません。

以下は、.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
4

2 に答える 2

2

.NETファイナライザーがJavaファイナライザーと同様に悪い考えであるかどうかはわかりませんが、ファイナライザー(プラットフォームに関係なく)のようなものから潜在的に(デッド)ロックコード(一番下にWin32条件呼び出しが表示されます)を使用することは間違いなく悪いことですアイディア。潜在的なロックのネイティブコードをクリーンアップするか、.NETレベルで緊急ブレーキタイムアウトを設定する必要があります

于 2012-08-15T15:31:24.127 に答える
1

質問が見つからなかったので、ここに正式な回答を投稿するのではなく、私が時々経験した同様のことについて話をします。

Javaオブジェクトに裏打ちされたJNIを介してオブジェクトを作成し、finalizeメソッド内でCオブジェクトをクリーンアップすることにしました。ただし、ファイナライズは非アプリケーションスレッドであるガベージコレクターから呼び出されるため、デッドロックを想定していました。ゴミを収集している間、ワールド全体が停止するため、ファイナライザーがロックに遭遇すると、すぐにデッドロックになります。したがって、ファントム参照と呼ばれるJavaメカニズムを使用することにしました。これらの「参照」(Cポインター)のそれぞれに番号をバインドすると、VMは参照されたオブジェクトを削除し、そのような参照をキューに入れます。また、必要に応じてこのデータを取得し、Cオブジェクトを削除できます。

少なくともあなたの問題は同じだと思います。

于 2012-08-15T15:27:30.057 に答える