You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FreeLibrary持续返回true的原因?DllImport加载原生DLL卸载失败

为什么FreeLibrary反复返回true,DLL始终无法卸载?

嘿,这个坑我之前踩过好几次!结合你用DllImport加载原生DLL的背景,以及你提到的技巧,问题大概率出在CLR对DLL引用的内部管理和你手动操作的计数不匹配上,具体原因和解决办法我给你拆解下:

核心原因分析

1. CLR的DllImport会维护独立的引用计数(且和你的手动操作共享底层计数)

当你用DllImport声明原生函数时,CLR会自动调用LoadLibraryEx加载DLL,并且在内部保留一个引用计数。这个计数和你通过LoadLibrary/FreeLibrary操作的是同一个底层系统计数,但CLR不会轻易释放它——除非它确定你再也不会用到该DLL的任何函数。

如果你用的技巧是通过GetModuleHandle获取句柄(没有额外调用LoadLibrary),那你循环调用FreeLibrary其实是在减少CLR持有的计数,但只要CLR还在缓存函数指针、或者还有未回收的委托引用,它可能会在你减完计数后自动重新加载DLL(再次增加计数),导致FreeLibrary一直返回true,陷入死循环。

2. 你可能不小心重复增加了引用计数

如果那个技巧里包含了重复调用LoadLibrary来获取句柄(而不是GetModuleHandle),那每次调用LoadLibrary都会给DLL的引用计数+1。这时候你循环调用FreeLibrary只是在抵消自己加的计数,永远碰不到CLR持有的那个计数,自然一直返回true,DLL也卸不掉。

3. 其他线程或进程组件在持续引用DLL

如果你的程序里还有其他线程在调用该DLL的函数,或者有其他组件(比如第三方库)也加载了同一个DLL,那每次你调用FreeLibrary减计数,其他地方又会通过调用函数或加载操作把计数加回去,导致循环永远停不下来。

可行的解决办法

方法1:放弃DllImport,手动控制加载卸载

这是最稳妥的方式:

  • 用LoadLibrary手动加载DLL,获取句柄
  • 用GetProcAddress获取你需要的函数指针
  • 用完后循环调用FreeLibrary直到返回false,彻底卸载
  • 这种方式你完全掌控引用计数,不会和CLR的内部管理冲突

方法2:强制CLR释放对DLL的依赖(不推荐,但应急可用)

如果你必须用DllImport,可以尝试以下步骤:

  1. 确保所有调用该DLL的代码都已经执行完毕,没有未完成的调用
  2. 强制触发垃圾回收:GC.Collect(); GC.WaitForPendingFinalizers();
  3. 用GetModuleHandle获取DLL句柄,然后循环调用FreeLibrary直到返回false

注意:这种方式不稳定,因为CLR可能会在之后的某个时刻重新加载DLL,导致未知错误。

方法3:检查DLL的DllMain逻辑

有些写得不好的DLL会在DLL_PROCESS_DETACH事件里重新加载自己(比如调用LoadLibrary),导致引用计数永远降不到0。你可以用工具(比如Dependency Walker)检查DLL的入口函数逻辑,排除这种情况。

内容的提问来源于stack exchange,提问作者Jan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 06:18:04