我有意在一个简单的C#程序中泄漏内存,以了解.NET如何管理这个方面。这是使用int[]数组完成的,每个数组的大小为1000万,每100 is就声明一次。数组的元素没有被“触摸”- -就像在赋值-中那样,以避免将数据带到进程的工作集中:
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 (由构建的工具)来查看内存是如何分配的。该版本是最近发布的版本(3.25,2018年发布),因此它了解托管堆。
Visual 2015被使用在带有8GB内存的x64 Windows 10机器上,用于编译和生成.exe文件。根据项目构建部分中的Platform target设置,可以看到与内存分配方式有关的不同结果,如下所示。
当Platform target设置为x86时,提交的内存将增长到接近2GB的标记,然后抛出内存不足的错误。这个值是预期的,因为2GB是x86体系结构上用户虚拟地址空间的限制(我不使用IncreaseUserVA,这可能会使这个值达到3 GB 编辑__:这不是完全正确的-参见下面的答案)。在本例中,VMMap的输出如下。与预期一样,大多数提交的数据都属于托管堆类别。

当Platform target设置为x64时,所提交的区域会像预期的那样不断增长。最终,该应用程序需要停止使用,因为它一直在分配内存。这也是意料之中的,因为只要可用的ram +分页文件的总量能够容纳增长,64位Win10框的理论限制是每个用户虚拟地址空间128 TB (受当前处理器的限制,因为它们只使用虚拟地址中可用的64位中的48位)。VMMap的输出低于。同样,大多数已提交的字节属于托管堆类别。

当Platform target设置为Any CPU并勾选Prefer 32-bit (这实际上是Visual 2015中的默认设置)时,结果就不那么简单了。首先,当提交的内存达到3.5GB时,抛出内存不足的异常。其次,托管堆中的私有字节仅增长到大约1.2GB,之后私有数据类别将注册下一个分配的数据。下面是VMMap的输出。

为什么分配发生在Any CPU + Prefer 32-bit设置的最后一段中所描述的情况?具体来说,为什么大量的数据列在私有数据下而不是托管堆下?
稍后编辑:添加图片内联,以更好的清晰度。
发布于 2019-02-05 22:31:07
在Windows64 Windows64 (wow64)下运行的LARGEADDRESSAWARE 32位进程具有4GB的用户模式虚拟地址空间(VAS),因为内核内存是64位,不需要映射到具有32位指针的4GB可寻址地址。而且你不需要用/3GB switch引导Windows就能得到它。
在为X86编译时,您可能希望在32位和64位平台上有相同的行为,因此不设置LARGEADDRESSAWARE标志是有意义的。而且,这可能是由向后兼容性所决定的。在很久以前,一些32位库(Mis)使用了高级指针位,因此历史上将32位程序限制为2GB是一种安全设置。
AnyCPU+Prefer 32位是一个较新的设置,默认情况下获取LARGEADDRESSAWARE设置,以便更好地访问64位平台上的资源。
https://stackoverflow.com/questions/54543938
复制相似问题