Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/275.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# CLR/从32位进程切换到64位进程后内存消耗高_C#_Memory_Memory Management_Memory Leaks_Clr - Fatal编程技术网

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

C# CLR/从32位进程切换到64位进程后内存消耗高,c#,memory,memory-management,memory-leaks,clr,C#,Memory,Memory Management,Memory Leaks,Clr,我有一个构建在.NETFramework4.5(C#)之上的后端应用程序(windows服务)。该应用程序在Windows Server 2008 R2服务器上运行,内存为64GB 由于我的依赖性,我曾经将此应用程序编译为32位进程(编译为x86)并运行,并使用/largeaddressware标志让应用程序在用户空间中使用超过2GB的内存。使用此配置,平均内存消耗(根据任务管理器中的“内存(专用工作集)”列)约为300-400MB 我之所以需要使用LargeAddressWare标志,并将其改

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

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

我之所以需要使用LargeAddressWare标志,并将其改为64位,是因为尽管300-400MB是的平均值,但偶尔这个应用程序会做一些事情,包括将大量数据加载到内存中(在内存不太有限的情况下,开发和管理此类内容会容易得多)

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

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

  • 根据“所有堆中的字节”计数器,内存总量约为600MB

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

  • 根据GC性能计数器,定期存在Gen0集合。事实上,“%Time In GC”计数器表示平均花费在GC上的时间为10-20%(考虑到应用程序的性质,这是有意义的——大量的信息和数据结构分配在短时间内使用)

  • 我正在该应用程序中使用服务器GC

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

我的问题是:

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

  • 为什么64位进程比32位进程占用更多内存?即使考虑到指针的大小是指针的两倍,也有很大的区别

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


谢谢

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


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

有几件事需要考虑:

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等工具进行详细分析。

嘿,谢谢您的回答。正如我所说,我很清楚指针大小的差异。即便如此,内存的总量还是远远大于两倍大小的内存。此外,我使用WinDbg检查分配的对象-所有对象的总大小(包括可用空间)约为内存大小的1/4(根据任务管理器)。我正在寻找解释,如果你有一个-我很高兴你分享。再次感谢。你推迟处理泄漏问题的时间太长了,忽略了两次。你不能再翻了。你必须找到漏洞,这是一个未经管理的漏洞。位图是标准的gobbler。我观察到,ASP.NET中.NET 4使用的内存是.NET 2-3.5的两倍多。专用工作集不是使用的内存。也被分页的是“使用”的内存(用于该词的某些定义)。使用计数器“专用内存”。对我来说很有意义:内存使用量不适合2GB,所以您增加了可用内存。现在,如果内存使用量超过2GB,请不要感到惊讶。事实上,从一开始你就应该怀疑这个300MB的数字。为什么2GB的地址空间不能容纳300MB的内存。要使我前面的评论可行,请查看32位和64位的专用内存计数器。内存使用率将在2倍以内。现在使用应用程序更改保存一些内存。