4

Excel アドインである .NET 3.5 SP1 アプリケーションがあります。AppDomainアプリケーションは、親(Excel の) ドメインと、すべての dll をロードする子ドメインに分割されます。アプリケーションを更新する場合は、子ドメインをアンロードし、ファイルを置き換えて再ロードします。

残念ながら、ドメインをアンロードすると 2 つのワーカー スレッドがアクティブになり、CPU サイクル (20 ~ 40%) を消費し始めます。

VS 2010 でデバッグすると、 の前後の瞬間に、AppDomain.UnloadExcel のメイン スレッド以外にコール スタックで生きているスレッドはありません。AppDomain.UnloadUnload をもう一度呼び出そうとするとAppDomainUnloadedException.

ProcessExplorer を使用すると、VS デバッガーが壊れた場合でも、2 つのスレッドがビジー状態で動作していることがわかります。シンボルがないため、コールスタックを調べても何もわかりません。

  • ntkrnlpa.exe+0x6eacb
  • ntkrnlpa.exe+0x2bfd0
  • hal.dll+0x2ef2
  • ntkrnlpa.exe+0x6a6cf
  • ntdll.dll+0xe514
  • mscorwks.dll+0x992d
  • mscorwks.dll+0x52568
  • mscorwks.dll+0x15b469
  • kernel32.dll+0xb729

WinDbg を使用すると、2 つのレネゲード スレッドのコールスタックを確認できます。それは常に同じことです:

  • 警告: スタック アンワインド情報は利用できません。次のフレームは間違っている可能性があります。
  • ntdll!KiFastSystemCallRet
  • mscorwks+0x992d
  • mscorwks!InstallCustomModule+0x1eca0
  • mscorwks!CorExitProcess+0x503b
  • kernel32!GetModuleFileNameA+0x1ba

子アセンブリをロード/アンロードするための非常に単純なテスト アプリケーションを作成しました。単純な 1 クラスのアセンブリでこれを行うと、問題なく動作します。実際のアプリケーションの子ドメインをロード/アンロードすると、同じ反逆スレッドがトリガーされます。

子ドメインを作成するコードは次のとおりです。

AppDomainSetup appSetup = new AppDomainSetup();
appSetup.ApplicationBase = baseDir;

var ps = new PermissionSet(System.Security.Permissions.PermissionState.Unrestricted);
return AppDomain.CreateDomain(name, null, appSetup, ps, null);

親ドメインから子ドメインへの通信は、プロキシとリフレクションを介して行われます。それを作成するコードは次のとおりです。

string assName = typeof(ApplicationProxy).Assembly.FullName;
string className = typeof(ApplicationProxy).FullName;

var obj = _childDomain.CreateInstanceAndUnwrap(assName, className, false, 
    System.Reflection.BindingFlags.Default,
    null, new object[]{_sessionGuid}, 
    CultureInfo.InvariantCulture,
    null, new Evidence(AppDomain.CurrentDomain.Evidence));

_proxy = (ApplicationProxy)obj;

私は問題を徹底的にグーグルで検索しましたが、同様の問題を抱えている人を見つけることができません。応募作品が10作品と大きくて掲載できません。

誰かが似たようなことに遭遇し、私にいくつかのヒントがあるかどうか疑問に思っています。それ以外の場合、問題を攻撃する方法について考えている人はいますか?

4

1 に答える 1

6

私を正しい道に導いてくれたハンスに感謝します。

ファイナライザーを持つクラスがいくつかあるので、それぞれにブレークポイントを置きます。そのうちの 1 つで、誰かが ThreadPool.QueueUserWorkItem を呼び出します。ワークアイテムは決して呼び出されず、代わりにこれら 2 つのスレッド (1 つは実行中のスレッドを中止し、1 つは処理を終了するため) を永遠に循環させます。

テストプロジェクトでテストしましたが、実際にそうです。

子供たちよ、教訓はマネージャーにスレッドコードを書かせてはいけないということだ。

于 2013-10-10T13:38:40.347 に答える