【问题标题】:CLR / High memory consumption after switching from 32-bit process to 64-bit processCLR / 从 32 位进程切换到 64 位进程后内存消耗高
【发布时间】:2014-09-24 00:41:16
【问题描述】:

我有一个基于 .NET Framework 4.5 (C#) 构建的后端应用程序(Windows 服务)。该应用程序运行在 Windows Server 2008 R2 服务器上,内存为 64GB。

由于我有依赖关系,我曾经将这个应用程序作为 32 位进程编译和运行(将其编译为 x86),并使用 /LARGEADDRESSAWARE 标志让应用程序在用户空间中使用超过 2GB 的内存。使用此配置,平均内存消耗(根据任务管理器中的“内存(私有工作集)”列)约为 300-400MB。

我需要 LARGEADDRESSAWARE 标志以及将其更改为 64 位的原因是,虽然 300-400MB 是 平均,但有时这个应用程序会做一些涉及加载的事情大量数据进入内存(当你的内存不是很有限时,开发和管理这类东西要容易得多)。

最近(在删除那些 x86 原生依赖项之后),我将应用程序编译更改为“任何 CPU”,所以现在,在生产服务器上,它作为 64 位进程运行。从我进行此更改开始,平均内存消耗(根据任务管理器)达到了新的水平:3-4 GB,而没有其他更改可以解释这种行为变化。

以下是有关当前状态的一些其他事实:

  • 根据“#Bytes in all heaps”计数器,内存总量约为600MB。

  • 在使用 WinDbg+SOS 调试进程时,!dumpheap -stat 显示大约有 250-300MB 空闲,但所有其他对象都远小于进程使用的内存总量。

  • 根据 GC 性能计数器,定期进行 Gen0 收集。事实上,“% Time in GC”计数器表明平均 10-20% 的时间花在 GC 上(考虑到应用程序的性质,这是有道理的 - 大量分配的信息和数据结构用于短时间)。

  • 我在这个应用程序中使用 Server GC。

  • 服务器上没有内存问题。它使用了大约 50-60% 的可用内存 (64GB)。

我的问题:

  • 为什么分配给进程的内存(根据任务管理器)与 CLR 堆的实际大小有很大差异(进程中没有非托管代码可以解释这一点)?

  • 为什么 64 位进程与以 32 位进程运行的相同进程相比占用更多内存?即使考虑到指针的大小是原来的两倍,也有很大的不同。

  • 我可以做些什么来降低内存消耗,或者更好地理解这个问题吗?

谢谢!

【问题讨论】:

  • 您推迟处理泄漏问题 far 的时间太长,将忽略位翻转了两次。你不能再翻转它。你必须找到泄漏,它是一个不受管理的泄漏。位图是标准的 gobblers。
  • 我观察到 .NET 4 在 ASP.NET 中使用的内存是 .NET 2-3.5 的两倍多。
  • 私有工作集不是使用的内存。它是“使用”的内存(对于该词的某些定义)也被分页。使用计数器“私人内存”。对我来说很有意义:内存使用量不适合 2GB,因此您增加了可用内存。现在,如果内存使用量超过 2GB,请不要感到惊讶。事实上,300MB 这个数字从一开始就应该让你怀疑。为什么 2GB 的地址空间不适合 300MB 的内存。
  • 为了使我之前的评论具有可操作性:查看 32 位和 64 位的私有内存计数器。内存使用率将在 2 倍以内。现在使用应用程序更改节省一些内存。

标签: c# memory memory-management memory-leaks clr


【解决方案1】:

有几点需要考虑:

1) 您提到您正在使用服务器 GC 模式。在服务器 GC 模式下,CLR 为机器上的每个 CPU 内核创建一个堆,这样在服务器进程中的多线程处理效率更高,例如Asp.Net 进程。每个堆有两个段:一个用于小对象,一个用于大对象。每个段以 4 GB 保留内存开始。基本上服务器 GC 模式会尝试在系统上使用更多内存来换取整体系统性能。

2) 当然,指针在 64 位上更大。

3) 由于堆更大,前台 Gen2 GC 在服务器 GC 模式下变得非常昂贵。所以 CLR 非常努力地减少前台 Gen2 GC 的数量,有时使用后台 Gen2 GC。

4) 根据使用情况,碎片可能成为一个真正的问题。我见过有 98% 碎片的堆(98% 的堆是空闲块)。

要真正解决您的问题,您需要获取 ETW 跟踪 + 内存转储,然后使用 PerfView 等工具进行详细分析。

【讨论】:

    【解决方案2】:

    64 位进程自然会使用 64 位指针,有效地使每个引用的内存使用量翻倍。某些平台相关变量(例如 IntPtr)也会占用双倍空间。

    您可以做的第一件事也是最好的事情是运行内存分析器来查看额外内存占用的确切来源。其他一切都是推测!

    【讨论】:

    • 您好,谢谢您的回答。正如我所说,我很清楚指针大小的差异。即便如此,内存总量还是比两倍大。此外,我使用 WinDbg 检查了分配的对象 - 所有对象的总大小,包括可用空间,大约是内存大小的 1/4(根据任务管理器)。我正在寻找对此的解释,如果你有一个 - 如果你分享,我会很高兴。再次感谢。
    猜你喜欢
    • 1970-01-01
    • 2017-03-05
    • 2011-01-01
    • 2013-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-08
    • 2010-09-12
    相关资源
    最近更新 更多