简体   繁体   English

CLR /从32位进程切换到64位进程后的高内存消耗

[英]CLR / High memory consumption after switching from 32-bit process to 64-bit process

I have a backend application (windows service) built on top of .NET Framework 4.5 (C#). 我有一个基于.NET Framework 4.5(C#)构建的后端应用程序(Windows服务)。 The application runs on Windows Server 2008 R2 server, with 64GB of memory. 该应用程序在Windows Server 2008 R2服务器上运行,具有64GB内存。

Due to dependencies I had, I used to compile and run this application as a 32-bit process (compile it as x86) and use /LARGEADDRESSAWARE flag to let the application use more than 2GB memory in the user space. 由于我的依赖关系,我曾经编译并运行这个应用程序作为32位进程(编译为x86)并使用/ LARGEADDRESSAWARE标志让应用程序在用户空间中使用超过2GB的内存。 Using this configuration, the average memory consumption (according to the "memory (private working set)" column in the task manager) was about 300-400MB. 使用此配置,平均内存消耗(根据任务管理器中的“内存(私有工作集)”列)约为300-400MB。

The reason I needed the LARGEADDRESSAWARE flag, and the reason i changed it to 64-bit, is that although 300-400MB is the average , once in a while this app doing stuff that involves loading a lot of data into the memory (and it's much easier to develop and manage this kind of stuff when you're not very limited memory-wise). 我需要LARGEADDRESSAWARE标志的原因,以及我将其更改为64位的原因是,虽然300-400MB是平均值 ,但偶尔这个应用程序做的事情涉及将大量数据加载到内存中(并且它是当你的记忆力不是很有限时,更容易开发和管理这类东西。

Recently (after removing those x86 native dependencies), I changed the application compilation to "Any CPU", so now, on the production server, it runs as a 64-bit process. 最近(在删除那些x86本机依赖项之后),我将应用程序编译更改为“Any CPU”,所以现在,在生产服务器上,它以64位进程运行。 Starting when I did this change, the average memory consumption (according to the task manager) got to new levels: 3-4 GB , when there is no other change that may explain this change in behavior. 从我做这个改变开始,平均内存消耗(根据任务管理器)达到了新的水平:3-4 GB ,当没有其他变化可以解释这种行为变化时。

Here are some additional facts about the current state: 以下是有关当前状态的一些其他事实:

  • According to the "#Bytes in all heaps" counter, the total amount of memory is about 600MB. 根据“所有堆中的#Bytes”计数器,内存总量约为600MB。

  • When debugging the process with WinDbg+SOS, !dumpheap -stat showed that there are about 250-300MB free, but all the other object was much less than the total amount of memory the process used. 使用WinDbg + SOS调试进程时,!dumpheap -stat显示大约有250-300MB空闲,但所有其他对象远远小于进程使用的内存总量。

  • According to the GC performance counters, there are Gen0 collections on regular basis. 根据GC性能计数器,定期有Gen0集合。 In fact, the "% Time in GC" counter indicates that 10-20% in average of the time spent on GC (which makes sense given the nature of the application - a lot of allocations of information and data structures that are in use for short time). 实际上,“GC中的%时间”计数器表明在GC上花费的时间平均为10-20%(考虑到应用程序的性质,这是有意义的 - 大量的信息和数据结构分配正在使用短时间)。

  • I'm using Server GC in this app. 我在这个应用程序中使用Server GC。

  • There is no memory problem on the server. 服务器上没有内存问题。 It uses about 50-60% of the available memory (64GB). 它使用大约50-60%的可用内存(64GB)。

My questions: 我的问题:

  • Why is a great difference between the memory allocated to the process (according to the task manager) and the actual size of the CLR heap (there is no un-managed code in the process that can explain this)? 为什么分配给进程的内存(根据任务管理器)和CLR堆的实际大小之间存在很大差异(流程中没有可以解释此问题的未托管代码)?

  • Why is the 64-bit process takes more memory compared to the same process running as 32-bit process? 与运行32位进程的进程相比,为什么64位进程占用的内存更多? even when considering that pointers takes twice the size, there's a big difference. 即使考虑到指针的大小是两倍,也会有很大的不同。

  • Can i do something to lower the memory consumption, or to have better understanding of the issue? 我可以做些什么来降低内存消耗,或者更好地理解这个问题吗?

Thanks! 谢谢!

There are a few things to consider: 有几点需要考虑:

1) You mentioned you're using Server GC mode. 1)您提到您正在使用服务器GC模式。 In server GC mode, CLR creates one heap for every CPU core on the machine, which is more efficient more multi-threaded processing in server processes, eg Asp.Net processes. 在服务器GC模式下,CLR为机器上的每个CPU核心创建一个堆,这在服务器进程(例如Asp.Net进程)中更有效地进行多线程处理。 Each heap has two segment: one for small objects, one for large objects. 每个堆都有两个段:一个用于小对象,一个用于大对象。 Each segment starts with 4 gb reserved memory. 每个段以4 gb保留内存开头。 Basically server GC mode tries to use more memory on the system to trade for overall system performance. 基本上,服务器GC模式尝试在系统上使用更多内存来交换整体系统性能。

2) Pointer is bigger on 64-bit, of course. 2)当然,指针在64位上更大。

3) Foreground Gen2 GC becomes super expensive in server GC mode due to heap is much larger. 3)由于堆大得多,前台Gen2 GC在服务器GC模式下变得非常昂贵。 So CLR tries super hard to reduce the number of foreground Gen2 GC, sometimes using background Gen2 GC. 因此CLR尝试超级减少前景Gen2 GC的数量,有时使用后台Gen2 GC。

4) Depending on usage, fragmentation can become a real issue. 4)根据使用情况,碎片可能成为一个真正的问题。 I've seen heaps with 98% fragmentation (98% heap is free blocks). 我已经看到了98%碎片的堆(98%堆是免费块)。

To really solve your problem, you need to get an ETW trace + a memory dump, and then use tools like PerfView for detailed analysis. 要真正解决您的问题,您需要获取ETW跟踪+内存转储,然后使用PerfView等工具进行详细分析。

A 64-bit process will naturally use 64-bit pointers, effectively doubling the memory usage of every reference. 64位进程自然会使用64位指针,有效地将每个引用的内存使用量加倍。 Certain platform-dependent variables such as IntPtr will also take up double the space. 某些与平台相关的变量(如IntPtr)也会占用两倍的空间。

The first and best thing you can do is to run a memory profiler to see where exactly the extra memory footprint is coming from. 您可以做的第一件也是最好的事情是运行内存分析器,以查看额外内存占用的确切位置。 Anything else is speculative! 其他任何东西都是投机的!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM