“ AnyCPU”平台目标上的内存分配模式

时间:2019-02-05 22:19:29

标签: c# .net memory

我故意在一个简单的C#程序中泄漏内存,以了解有关.NET如何管理此方面的更多信息。这是使用int[]数组来完成的,每个数组的大小为1000万,每100ms声明一次。为了不将数据带入流程的工作集中,未“触摸”数组的元素(如分配值一样):

const int BlockSIZE = 10000000;  // 10 million
const int noOfBlocks = 500;
int[][] intArray = new int[noOfBlocks][];

for (int k = 0; k < noOfBlocks; k++) {
    intArray[k] = new int[BlockSIZE];
    Console.WriteLine("Allocated (but not touched) for array {0}: {1} bytes", k, BlockSIZE);
    System.Threading.Thread.Sleep(100);
}

我正在使用VMMap(由Mark Russinovich构建的工具)来查看如何分配内存。该版本是最新版本(3.25,于2018年发布),因此它了解托管堆。

Visual Studio 2015在具有8 GB RAM的x64 Windows 10计算机上使用,以编译和生成.exe文件。根据项目“构建”部分中的Platform target设置,可以看到与内存分配方式有关的不同结果,如下所示。

Platform target设置为x86时,在抛出内存不足错误之前,已提交的内存会增长到接近2 GB的标记。该值是可以预期的,因为x86体系结构上的用户虚拟地址空间限制为2 GB(我没有使用GrowthUserVA,这会使该空间最多增加3 GB, 稍后编辑 :这并不完全正确-请参阅下面的David回答)。在这种情况下,VMMap的输出如下。正如预期的那样,大多数已提交数据都属于“托管堆”类别。

Platform target= x64

Platform target设置为x64时,承诺区域将继​​续增长,这与预期的一样。最终,由于该应用程序不断分配内存,因此需要将其终止。这也是可以预料的,因为只要可用的ram +页面文件的总数可以容纳增长,则64位Win10盒的理论限制是每个用户虚拟地址空间128 TB(受当前处理器的限制)因为它们仅使用虚拟地址中可用的64位中的48位)。 VMMap的输出如下。同样,大多数已提交的字节都属于“托管堆”类别。

enter image description here

Platform target设置为Any CPU并勾选了Prefer 32-bit时-这实际上是Visual Studio 2015中的默认设置-结果不是那么简单。 首先,当提交的内存达到约3.5 GB时,将引发内存不足异常。 第二,托管堆中的专用字节仅增长到约1.2 GB,之后,“专用数据”类别将注册接下来要分配的数据。 VMMap的输出如下。

enter image description here

为什么如上段所述为Any CPU + Prefer 32-bit设置进​​行分配?具体来说,为什么在“私有数据”下而不是“托管堆”下列出大量数据?

稍后编辑:内联添加图片以提高清晰度。

1 个答案:

答案 0 :(得分:3)

LARGEADDRESSAWARE 32位进程在Windows下运行于Windows64(wow64)上,具有4GB的用户模式虚拟地址空间(VAS),因为内核内存为64bit,不需要映射到可使用32bit指针寻址的4GB。而且您不必使用/3GB switch来启动Windows即可。

针对X86进行编译时,您可能会期望在32位和64位平台上具有相同的行为,因此不要设置LARGEADDRESSAWARE标志是有意义的。同样,这可能是由于向后兼容所致。在非常时代,一些32位库(误用)使用了高位指针,因此从历史上讲,将32位程序限制为2GB是一种安全设置。

AnyCPU +首选32位是一个较新的设置,默认情况下设置为LARGEADDRESSAWARE,以便您可以更好地访问64位平台上的资源。