【问题标题】:Why does Silverlight leak memory when using COM?为什么使用 COM 时 Silverlight 会泄漏内存?
【发布时间】:2011-05-12 17:16:23
【问题描述】:

我们在 Out Of Browser Silverlight 应用程序中托管旧版 COM 组件时发现了这个问题,首先认为这是我们的 COM 组件的问题。

但是,将其缩小到托管可以想象的最基本的 COM 组件仍然存在内存泄漏。这个用于测试的 COM 组件是用 .NET 编写的,每次触发计时器时都会将事件简单地发送回 Silverlight 应用程序。每个事件仅包含一个字符串。

运行 Silverlight 应用程序时,进程内存使用量不断增长。探查器显示托管内存没有增加,这表明 Silverlight 运行时/COM 实现中存在泄漏。

有没有其他人看到过这个问题,如果有,您是否能够解决它?

编辑: 现在可以在http://bitbucket.org/freed/silverlight-com-leak 上获得 Repro 项目

【问题讨论】:

  • 谁在分配字符串?可能是字符串内存泄漏。如果 COM 组件正在分配字符串,它也必须释放它。
  • 在我的测试示例中,COM 组件是在 .NET 中实现的,字符串只是一个普通的托管字符串。我不知道旧版 COM 组件如何分配其字符串,但同一组件在 .NET 中托管时不会泄漏。
  • 好吧,你说服了我。这并不难,没有其他可看的。您需要 Microsoft 支持来解决互操作错误,并准备好您的信用卡。
  • @Hans - 我在 Silverlight 论坛 (forums.silverlight.net/forums/p/210055/494295.aspx) 上发布了一个错误报告,希望我能得到一些官方反馈。
  • @Freed:你能把代码贴出来吗?

标签: silverlight com memory-leaks


【解决方案1】:

查看您的代码,您来回传递的字符串是(11 个字符 + 终止零)= unicode 中的 24 个字节。在 COM 自动化中,使用 BSTR 为前导指针(32 位)添加 4 个字节,然后将其乘以 10000,即 10000 * 28 = 280000 字节。

这意味着每毫秒(计时器的值为 1)您将分配大量内存,而在 .NET 中,可能会在大对象堆(> 85000 字节)中分配 280000 字节的块。大多数情况下,重击 LOH 的结果是......内存问题,例如:Large Object Heap Fragmentation

这也许是你应该检查的。要测试的一件简单的事情是减小 BigMessage 的大小。您还可以深入了解 WinDBG:http://blogs.msdn.com/b/tess/archive/2008/08/21/debugging-silverlight-applications-with-windbg-and-sos-dll.aspx 并查看幕后的真实情况。

【讨论】:

    【解决方案2】:

    确保 COM 组件正在释放它分配的所有字符串。

    【讨论】:

    • 遗留组件本身可能有泄漏,但测试 COM 组件仅使用托管内存...
    • @Freed:可能是这样,但底层架构仍然必须分配 BSTR 和释放 BSTR。仍然存在 COM 边界。我的期望是,由于一些引用计数,这些没有被释放,因此被泄露。
    • 好的,经过一番调查,似乎字符串一旦编组为 System.String 就应该被释放。不确定 Silverlight 是否会这样做,但我希望它会这样做。如果没有看到代码,将很难解决这个问题 - 但是,您的描述中有一些点让我很感兴趣,所以代码真的很有用。
    • 如上所述,测试解决方案可在bitbucket.org/freed/silverlight-com-leak 获得。
    【解决方案3】:

    不熟悉 Silverlight,但另一个可能导致互操作问题的原因是事件处理:http://www.codeproject.com/KB/cs/LingeringCOMObjects.aspx

    【讨论】:

    • 谢谢,但是我们只实例化了一次 COM 组件,泄漏是由于事件被触发,而不是组件被释放和创建。
    • .NET 将处理所有的 COM 事件,无论您是否愿意。这意味着本机内存将一直存在,直到您强制进行垃圾收集。但是如果你强制垃圾收集并且内存仍然泄漏,那么它可能是其他一些问题。
    【解决方案4】:

    会不会有原生资源没有被垃圾回收?也许这是调用 GC.Collect 可能有益的非常少数情况之一。有趣的阅​​读here

    只是为了测试,你可以调用 GC.Collect 几次(甚至三次),看看会发生什么(我不敢相信我实际上是在暗示这个......)。

    【讨论】:

    • 强制 GC 确实会稍微降低托管内存,这是意料之中的,但仍有大量本机内存不受影响
    猜你喜欢
    • 2011-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-09
    相关资源
    最近更新 更多