处理带有内存泄漏的非托管DLL

Hug*_*une 10 c# memory-leaks memory-management unmanaged appdomain

我有一个ac#应用程序,它依赖于第三方非托管程序集来访问某些硬件.

非托管代码存在内存泄漏,每次访问后内存消耗会增加~10mb.问题是众所周知的; 没有bugfix可用.

有没有办法可以继续使用这个程序集而无需定期重启?

我尝试创建一个单独的AppDomain,将有问题的代码加载到该AppDomain中appDomain.CreateInstanceAndUnwrap(),然后通过以下方式卸载域AppDomain.Unload().但是,这显然不会释放该域使用的非托管内存,只释放托管内存.

我还可以将应用程序拆分为两个独立的部分,并仅重新启动具有非托管dll的部分.然而,这将意味着重大的重新设计,并且可能导致大量的减速,因为必须在这两个部分之间交换大量数据.

是否有另一种方法可以驯服这个漏出的程序集并强制它释放内存而不重新启动.

ang*_*son 6

您描述的方式是,dll 正在分配非托管内存。不幸的是,正如您已经发现的那样,这种内存不会受到卸载应用程序域的行为的影响。

您有几个选择,但我认为它们中的任何一个都不吸引人:

  1. 您可以继续在主应用程序中使用该 dll。您可以告知您的用户/客户他们需要有大量可用内存,但需要不时重新启动应用程序。您可能希望在程序实际开始崩溃之前检测内存不足的情况,以温和地促使用户重新启动它,而不是仅仅因为异常而严重崩溃。
  2. 您可以尝试深入研究 dll 的数据结构。如果 dll 确实在更改(即新版本即将发布),我强烈建议您努力依靠作者来修复内存泄漏。但是,这似乎不太可能,因为我很确定如果出现新版本,泄漏得到修复。因此,将您的代码直接绑定到该 dll 的内部可能是一种解决方案。访问引用非托管内存的实际指针可能允许您根据需要手动释放它。
  3. 您可以将问题隔离到一个单独的进程。更多关于下面的内容。
  4. 您可以重新实现 dll 的功能。

这里可能有第 5 个或第 6 个选项,但认为以上 4 个选项涵盖了我脑中浮现出来的东西。

关于将它隔离到一个单独的进程中,这是我首先要尝试做的:

我会启动一个进程,并使用您能找到的最快的进程内通信通道向它发送请求。管道似乎很适合,或者内存映射文件。

然后,在那个单独的进程中,您可以检测内存不足的情况,希望能提前一点,以便您可以建议主程序考虑启动一个替换进程。

主进程然后可以这样做,但不是等待其他进程完全启动,它可以继续向即将死亡的实例发送更多请求,在切换之前将其填满一点到新实例并要求旧实例终止。

这将最大限度地减少停机时间,但代价是在转换期间暂时有一个额外的进程处于活动状态。

所有这些在很大程度上取决于您拥有的实际场景。如果您需要每秒调用此 dll 100 或 1000 次,则在任何情况下都可能无法进行进程内通信。