我们有一个围绕MonoRail和NHibernate构建的ASP.NET应用程序,我注意到在使用64位模式或32位模式运行它时会出现奇怪的行为。所有内容都编译为AnyCPU,并且在两种模式下运行良好,但内存使用量差别很大。
查看ANTS的以下快照:
32bit_snapshot:
VS
64bit_snapshot:
两个快照的使用场景几乎相同(我在两次运行中都点击了相同的页面)。
首先,为什么未使用的内存在64位模式下如此之高?为什么非托管内存的大小是64位模式的4倍?
对此的任何见解都会非常有用。
答案 0 :(得分:15)
64位进程的初始内存分配远高于等效32位进程的初始内存分配。
理论上,这允许垃圾收集运行得更少,这应该可以提高性能。它还有助于碎片化,因为一次分配更大的内存块。
本文:http://blogs.msdn.com/b/maoni/archive/2007/05/15/64-bit-vs-32-bit.aspx给出了更详细的解释。
您看到的非托管内存使用率较高可能是因为在32位模式下运行的.NET对象使用最少12个字节(8个字节+ 4个字节引用),而64位中的同一个对象需要24个字节(12个字节+ 8个字节的引用)。
另一篇文章更完整地解释了这一点:http://www.simple-talk.com/dotnet/.net-framework/object-overhead-the-hidden-.net-memory--allocation-cost/
答案 1 :(得分:3)
64位系统内存问题的标准答案是默认情况下大多数内存操作都与16个字节对齐。对128位XXM寄存器的存储器读取预期与16字节边界对齐。堆栈中的两个参数占用的内存量与三个相同(返回地址占用丢失的8个字节)。 Gnu malloc将分配的区域对齐到16字节边界。
如果分配的单位的大小很小,那么开销将是巨大的:首先是对齐数据的开销,然后是对齐与数据相关联的簿记的开销。
另外我预测在64位系统中数据结构已经发展:代替二进制,或2-3-4,平衡,展开或任何树,可能有一个基数16树,可以有一个树很多松弛但可以使用保证存在的SSE扩展快速处理。
答案 2 :(得分:2)
我不能直截了当地告诉你发生了什么,但实际上做了很好的猜测。 32位进程与64位进程具有不同的内存限制。 CLR将经常在32位进程中运行GC。您可以通过图表上的峰值看到这一点。但是,当您运行64位进程时,在内存不足之前不会调用GC。这取决于您的系统总内存使用量。
在数字中,您的32位进程只能分配大约1gig,而您的64位可以分配所有内存。在32位进程中,GC将更快地开始清理,因为当程序使用大量内存时,程序将会受到影响。当您的总系统内存低于某个垃圾箱时,64位进程上的CLR将开始清理。