我有意在一个简单的C#程序中故意泄漏内存,以更好地了解.NET如何管理这个方面。这是通过声明每100ms一个大小为1000万的
我正在使用由Mark Russinovich开发的VMMap工具来查看内存分配情况。版本是最新的(2018年发布的3.25版本),因此它了解托管堆。
在x64 Windows 10机器上使用Visual Studio 2015编译并生成.exe文件,RAM为8 GB。根据项目构建部分中的平台目标设置,可以看到与内存分配方式相关的不同结果,如下所示。
当平台目标设置为x86时,已提交的内存增长直到接近2 GB,然后抛出内存不足错误。这个值是可以预期的,因为2 GB是x86体系结构用户虚拟地址空间的限制(我没有使用IncreaseUserVA,否则会将其提升到3 GB。稍后编辑:这不完全正确-请参见David的答案)。在这种情况下,VMMap的输出如下所示。大部分提交的数据都属于托管堆类别,这是可以预料的。 当
后续编辑:内联添加图片以获得更好的清晰度。
int[]
数组来完成的。为了不将数据带入进程的工作集中,数组的元素没有被“触摸”,即未赋值。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);
}
我正在使用由Mark Russinovich开发的VMMap工具来查看内存分配情况。版本是最新的(2018年发布的3.25版本),因此它了解托管堆。
在x64 Windows 10机器上使用Visual Studio 2015编译并生成.exe文件,RAM为8 GB。根据项目构建部分中的平台目标设置,可以看到与内存分配方式相关的不同结果,如下所示。
当平台目标设置为x86时,已提交的内存增长直到接近2 GB,然后抛出内存不足错误。这个值是可以预期的,因为2 GB是x86体系结构用户虚拟地址空间的限制(我没有使用IncreaseUserVA,否则会将其提升到3 GB。稍后编辑:这不完全正确-请参见David的答案)。在这种情况下,VMMap的输出如下所示。大部分提交的数据都属于托管堆类别,这是可以预料的。 当
平台目标
设置为 x64
时,承诺的区域会像预期的那样不断增长。最终应用程序需要被杀死,因为它不断地分配内存。这也是预期的,因为只要可用的 RAM + 分页文件的总数量可以容纳增长,64位Win10框的理论限制是每个用户虚拟地址空间128 TB(由于当前处理器仅使用64位中的48位作为虚拟地址,因此受限)。VMMap的输出如下所示。同样,大部分已承诺的字节属于托管堆类别。
当 平台目标
设置为 Any CPU
且勾选了 Prefer 32-bit
- 这实际上是在 Visual Studio 2015 中的默认设置 - 结果并不那么简单。首先,当已提交内存达到约3.5 GB时,会抛出内存不足异常。其次,在托管堆中,私有字节仅增长到约1.2 GB,之后 Private Data 类别会注册下一个分配的数据。VMMap 的输出如下。
后续编辑:内联添加图片以获得更好的清晰度。
int
占用4个字节,而1024个int数组元素将完全填充一个常规的4KB页面(int数组将强制进行连续分配)。仅触摸第1024个元素将触发内存管理器将整个页面带入内存,作为工作集的一部分。只要周围有空闲内存,并且这些页面都没有移动到分页文件中,就可以将整个已提交的内存视为工作集的一部分。我的理解正确吗? - Mihai Albert