繁体   English   中英

卸载 NativeAOT 编译 dll

[英]Unloading NativeAOT compiled dll

用.NET 7的NativeAOT编译。 我们现在可以加载 C# dll 作为常规 Win32 模块。

HMODULE module = LoadLibraryW("AOT.dll");
auto hello = GetProcAddress(module, "Hello");
hello();

这工作正常并在控制台中打印一些东西。

但是,卸载dll的时候,根本就不行。 无论我调用FreeLibrary("AOT.dll")多少次, GetModuleHandle("AOT.dll")仍然返回模块的句柄,这意味着它没有成功卸载。

我的“疯狂猜测”是运行时有一些后台线程仍在运行(GC?),所以我枚举了所有线程并使用NtQueryInformationThread来检索每个线程的起始地址,然后使用GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS调用GetModuleHandleEx以获取线程启动的模块,结果如下。

前:

THREAD ID      = 7052
base priority  = 8
delta priority = 0
Start address: 00007FF69D751613
Module: 00007FF69D740000 => CppRun.exe


THREAD ID      = 3248
base priority  = 8
delta priority = 0
Start address: 00007FFEF1F42B20
Module: 00007FFEF1EF0000 => ntdll.dll


THREAD ID      = 7160
base priority  = 8
delta priority = 0
Start address: 00007FFEF1F42B20
Module: 00007FFEF1EF0000 => ntdll.dll

后:

THREAD ID      = 7052
base priority  = 8
delta priority = 0
Start address: 00007FF69D751613
Module: 00007FF69D740000 => CppRun.exe


THREAD ID      = 3248
base priority  = 8
delta priority = 0
Start address: 00007FFEF1F42B20
Module: 00007FFEF1EF0000 => ntdll.dll


THREAD ID      = 7160
base priority  = 8
delta priority = 0
Start address: 00007FFEF1F42B20
Module: 00007FFEF1EF0000 => ntdll.dll


THREAD ID      = 5944
base priority  = 8
delta priority = 0
Start address: 00007FFEF1F42B20
Module: 00007FFEF1EF0000 => ntdll.dll


THREAD ID      = 17444
base priority  = 10
delta priority = 0
Start address: 00007FFE206DBEF0
Module: 00007FFE206D0000 => AOT.dll

“CppRun.exe”是我的测试应用程序。

如您所见,生成了两个额外的线程。 一个来自 ntdll (5944),一个来自我的 AOT 编译 dll (17444)。

我不知道“AOT.dll”中剩余的线程是做什么用的(也许是 GC?),但我成功地强制终止了它(我知道这绝对是不健康的)。

但是,当我尝试在 ntdll (5944) 中打开线程时,它会抛出异常

为此操作指定了一个无效的线程,句柄 %p。 可能指定了线程池工作线程

鉴于此,我假设 .NET 在初始化期间启动了一个线程池工作者? 如何停止该池并卸载 dll?

或者,是否有更好的方法来卸载 NativeAOT 编译的 dll?

更新:我已经连接了CreateThreadPool function,但运行时没有调用它。 仍在试图弄清楚是什么产生了那个线程。

编辑:

NativeAOT(aka CoreRT)编译的 dll 一开始是无法加载的,但微软后来由于 memory 泄漏和进程退出崩溃而阻止了该功能。 有关详细信息,请参阅此 PR 这个答案只是使用绕行钩子恢复功能,不处理 memory 泄漏或崩溃 需要您自担风险使用它。

我能够通过手动释放由 .NET 创建的 FLS(光纤本地存储)来防止访问冲突崩溃。 是一个简单的演示。

原回答如下:

原来线程被 Windows 10 用于并行库加载(TppWorkerThread),这不是问题所在。

我最终使用这个方便的工具检查了 winapi 调用,发现 .NET 正在使用GET_MODULE_HANDLE_EX_FLAG_PIN标志调用GetModuleHandleEx ,从而阻止模块卸载。 .NET 调用 GetModuleHandleEx

所以我连接了GetModuleHandleEx来拦截调用并移出标志。 哒哒。 现在我可以毫无问题地卸载 NativeAOT 编译的 dll。

我知道这种方法很老套,但是,嘿,它有效。 如果有人碰巧有更好的解决方案,请告诉我。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM