【问题标题】:Handling memory leaks caused by an external assembly处理由外部程序集引起的内存泄漏
【发布时间】:2012-10-15 16:17:28
【问题描述】:

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

using (ExternalWidget widget = new ExternalWidget())
{
    widget.DoSomething();
}

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

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

【问题讨论】:

  • 创建一个演示问题的小示例程序并联系库的作者。
  • 如果您知道内存泄漏的原因,您可能可以使用反射来修复它(我们必须使用旧版本的 Infragistics 控件库来做到这一点)。
  • 你怎么知道它没有清理非托管资源?
  • 您也可以将外部组件拆开,修复泄漏,然后重新组装。
  • @Dan Puzey 我使用了 ANTS Memory Profiler,它显示每次调用代码时我的所有 .NET 堆都被释放。但是,非托管内存和私有字节总数继续上升。

标签: c# .net memory-management memory-leaks dispose


【解决方案1】:

如果是真正的非托管内存泄漏并且您无法更改代码,那么您几乎无能为力。框架无法处理该问题,也无法清理该代码。

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

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

这留下了过程级别。我建议在 WCF 中创建一个服务合同,模拟对 ExternalWidget 的调用以及 Shutdown 方法。

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

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

然后,您将拨打电话,当您处理完ExternalWidget 的实例后,拨打Shutdown; EXE 会知道停止等待,然后进程将退出,操作系统将回收内存。

当然,这里有一个巨大的开销,所以如果你发现你正在做很多调用并且不需要为每组调用一个新的进程,你可以扩展将想法转化为一个服务,该服务会计算调用次数,然后在需要时回收进程(该服务仍然需要掏空,否则 将耗尽资源)。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-21
    • 2018-08-27
    • 2020-05-13
    • 2011-01-13
    • 2012-07-01
    • 1970-01-01
    相关资源
    最近更新 更多