处理由外部程序集引起的内存泄漏

mar*_*d13 6 .net c# dispose memory-leaks memory-management

我需要使用一个我无法修改的外部组件.假设我使用该程序集中的类,如下所示:

using (ExternalWidget widget = new ExternalWidget())
{
    widget.DoSomething();
}
Run Code Online (Sandbox Code Playgroud)

每次调用此代码时,都会泄漏非托管内存.ExternalWidget实现IDisposable,我已将其包装在一个using语句中,但ExternalWidget不清理其非托管资源.

由于我无法访问ExternalWidget代码,因此无法以正确的方式解决此问题.有没有其他方法可以释放所使用的内存资源ExternalWidget

cas*_*One 4

如果这是真正的非托管内存泄漏并且您无法更改代码,那么您无能为力。框架无法识别这一点,也无法清理该代码。

这种情况下的方法是隔离该组件。这意味着访问它会产生大量开销,但您无能为力。

您无法在另一个应用程序域中运行代码,因为非托管代码没有应用程序域的概念。

这就剩下流程层面了。我建议在 WCF 中创建一个服务合约,模拟对ExternalWidget方法的调用Shutdown

ExternalWidget然后,您将创建一个 EXE,它将通过命名管道绑定公开此合约(通过会话,以便您可以保留该实例,除非每个调用都是无状态的)。

作为 EXE 的参数,它将采用唯一标识符(使用 )Guid并将其用作设置 WCF 服务端点的一部分。

然后,您将进行调用,当您完成 的实例后ExternalWidget,调用Shutdown; EXE 会知道停止等待,然后进程将退出,操作系统将回收内存。

当然,这里有大量的开销,因此,如果您发现自己正在进行大量调用并且不需要为每组调用创建一个新进程,您可以将这个想法扩展到一个对调用进行计数的服务中,并且然后在需要时回收该进程(该服务仍然需要退出,否则耗尽资源)。

请注意,如果这是托管内存问题,那么您始终可以启动一个新的应用程序域,在那里运行代码(根据需要来回整理结果),然后释放该应用程序域。