我有一个基于 .NET Framework 4.5 (C#) 构建的后端应用程序(Windows 服务)。应用运行在Windows Server 2008 R2服务器上,内存为64GB。
由于存在依赖关系,我曾经将此应用程序编译为 32 位进程(将其编译为 x86)并使用/LARGEADDRESSAWARE 标志让应用程序在用户空间中使用超过 2GB 的内存。使用此配置,平均内存消耗(根据任务管理器中的“内存(专用工作集)”列)约为 300-400MB。
我需要 LARGEADDRESSAWARE 标志的原因,以及我将其更改为 64 位的原因,是虽然 300-400MB 是平均值,但偶尔这个应用会做一些涉及加载的事情大量数据进入内存(当你的内存不是很有限时,开发和管理这类东西要容易得多)。
最近(在删除那些 x86 native 依赖项之后),我将应用程序编译更改为“任何 CPU”,因此现在,在生产服务器上,它作为 64 位进程运行。从我进行此更改开始,平均内存消耗(根据任务管理器)达到了新的水平:3-4 GB,此时没有其他更改可以解释此行为更改。
以下是关于当前状态的一些额外事实:
根据“#Bytes in all heaps”计数器,内存总量约为 600MB。
当使用 WinDbg+SOS 调试进程时,!dumpheap -stat 显示大约有 250-300MB 空闲,但所有其他对象远远少于进程使用的内存总量。
根据 GC 性能计数器,定期进行 Gen0 回收。事实上,“GC 时间百分比”计数器表明平均 10-20% 的时间花费在 GC 上(考虑到应用程序的性质,这是有道理的——大量的信息和数据结构分配用于很短的时间)。
我在此应用中使用服务器 GC。
服务器上没有内存问题。它使用大约 50-60% 的可用内存 (64GB)。
我的问题:
为什么分配给进程的内存(根据任务管理器)与 CLR 堆的实际大小(进程中没有非托管代码可以解释这一点)之间存在巨大差异?
与作为 32 位进程运行的同一进程相比,为什么 64 位进程占用更多内存?即使考虑到指针占用两倍的大小,也有很大的不同。
我可以做些什么来降低内存消耗,或者更好地理解这个问题吗?
谢谢!
最佳答案
有几点需要考虑:
1) 您提到您正在使用服务器 GC 模式。在服务器 GC 模式下,CLR 为机器上的每个 CPU 核心创建一个堆,这样在服务器进程中进行更高效的多线程处理,例如Asp.Net 进程。每个堆有两个段:一个用于小对象,一个用于大对象。每个段以 4 GB 保留内存开始。基本上服务器 GC 模式试图在系统上使用更多内存来换取整体系统性能。
2) 当然,指针在 64 位上更大。
3) 由于堆更大,前台 Gen2 GC 在服务器 GC 模式下变得非常昂贵。所以 CLR 非常努力地减少前台 Gen2 GC 的数量,有时使用后台 Gen2 GC。
4) 根据使用情况,碎片可能成为一个真正的问题。我见过有 98% 碎片的堆(98% 的堆是空闲 block )。
要真正解决你的问题,你需要获取ETW trace + 内存转储,然后使用PerfView等工具进行详分割析。
关于c# - CLR/从32位进程切换到64位进程后内存消耗高,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25069582/