【问题标题】:.NET 4 WCF memory issue.NET 4 WCF 内存问题
【发布时间】:2011-11-21 02:08:04
【问题描述】:

我遇到的问题是,我的 ASP.NET 4 MVC 2 + WCF 应用程序在 Windows 2008 64 位 应用程序中使用了大量内存运行几分钟后几乎所有可用内存(8 GB)(我们确实有几个工作进程正在运行)。

在使用 ANTS Memory Profiler 进行分析后,它显示出一些有趣的结果:

  1. .NET 托管内存从 15 MB 增加到 40 MB,但这要归功于我们在程序中所做的缓存机制。 但是 .NET 本身分配了将近 180 MB 的可用空间,这是出乎意料的。
  2. 在负载测试运行大约 3 分钟后,非托管内存大小显着增加直到 120 MB(尽管我们的应用程序没有明确使用任何 P/Invoke 或 COM 对象。但是我们确实使用了一些在使用后释放的 COM+ 对象在 finally 块中)。
  3. 内存变得支离破碎。
  4. 上述第 1 项和第 2 项导致整个应用程序在负载测试运行几分钟后使用大约 350 MB,但如果我们不停止测试,它将继续进一步增长.

根据上面的第 1 项,我测试了一些应用程序以测试问题是由于我们的应用程序还是 WCF 引起的。 测试应用程序只是将 XML 数据(大约 300KB)加载到多线程应用程序中的数据集。当逻辑存储在 EXE 程序中时,应用程序从完成后的 24 MB 私有字节中仅使用 200 KB(从 40 KB 开始的额外 120 KB 用于未使用的内存)托管内存(这是可以接受的); 但当逻辑托管在 WCF 中时,应用程序使用 66 MB 托管内存(从 64 MB 可用/未使用托管内存开始,额外增加 61 MB)。所以看来WCF / ASP.NET是导致内存增加很多的)。

  1. 为什么 .NET 在堆中分配这么多空闲空间? 了解空闲空间可能是在内存快照过程中被 GC-ed 的 Gen 0/Gen 1/Gen 2,但我没有认为应用程序真的用掉了那么多内存。
  2. WCF 的行为是否正常?如果是,有什么方法可以改变行为以减少内存占用?
  3. 如何发现非托管内存泄漏,尤其是我没有明确使用非托管代码?

感谢您对上述问题的建议。

提前致谢,

威利

【问题讨论】:

  • 这里没有任何有用的信息...使用 350 MB 可能是正常的,但与 8GB 相比还有很长的路要走。稍后运行您的分析器,然后使用它找出内存的去向。
  • 对 WCF 的调用频率如何?您可能会看到用于处理尚未收集的消息的临时缓冲区

标签: .net wcf memory-management garbage-collection


【解决方案1】:

WCF 使用临时缓冲区来处理消息。您认为的内存泄漏可能是尚未收集的临时缓冲区。

为避免在 WCF 使用 BufferManager 重用缓冲区时一直创建新缓冲区,上限为 maxBufferPoolSize(链接到元素 here)指定的限制,默认为 512KB。任何超出此限制的请求都会导致创建新的缓冲区,这些缓冲区永远不会被重用并且必须被垃圾收集。

另一个要检查的选项是 maxBufferSize,它限制了 BufferManager 可以返回的最大缓冲区大小。较大的缓冲区不会被池化,必须进行垃圾收集。如果您使用大型消息,则可以通过增加此属性来减少临时缓冲区。

尝试增加maxBufferPoolSize 看看是否可以减少内存使用量。我强烈建议不要将其最大化,因为池中的缓冲区在应用程序域(即应用程序池)回收之前永远不会释放。一段时间的高流量可能会导致大量内存被使用而从未释放。

【讨论】:

    【解决方案2】:

    关于“非托管内存泄漏”,我前段时间遇到过这样一个案例,经过一番挖掘,它是一个 ADO.NET 提供程序 - 用更新版本修复了这个问题 :-)

    至于其余部分 - 尝试将其放入配置中:

    <Configuration>
        <runtime>
            <gcServer enabled=“true“ />
        </runtime>
    </Configuration>
    

    除此之外,恕我直言,WCF 并没有什么特别之处...可能会像任何 .NET 应用程序一样存在内存泄漏(例如,事件处理程序和静态处理程序/对象在未正确取消订阅时会造成内存泄漏)...

    【讨论】:

    • 感谢您的反馈。我将尝试此配置并检查 ADO.NET 是否导致任何非托管内存泄漏。
    【解决方案3】:

    凭直觉:您是否订阅了任何静态事件或长寿命对象中的事件?

    • 订阅静态事件的对象将永远存在(或直到取消订阅)。
    • 订阅了对象事件的对象将在该对象的整个生命周期内都存在(或直到取消订阅)。

    因此,请确保您在上述任何一种情况下都努力退订事件。

    【讨论】:

    • 一种常见的模式,但不太可能在几分钟内吃掉 8GB。
    • @HenkHolterman,在“普通”客户端应用程序中 - 也许。但是服务器应用程序,尤其是在负载测试下的应用程序,可能就完全不同了。
    • @branko-dimitrijevic:谢谢,我没有使用太多事件处理程序(主要在代码中使用接口或委托),所以这不是问题的根本原因。
    猜你喜欢
    • 2011-06-12
    • 2011-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-08
    • 1970-01-01
    • 1970-01-01
    • 2011-10-25
    相关资源
    最近更新 更多