为什么在使用对象之前不会运行实例化对象?

时间:2016-06-25 18:08:45

标签: c# memory-management jit

在C#中我曾经说过,如果我运行以下代码,对我的记忆没有任何影响:

Console.WriteLine("press a key to allocate the memory");
Console.ReadKey();
double[] hudgeBunchOfMemory = new double[100000000];
Console.WriteLine("allocated");
Console.ReadKey();

但是如果我遍历数组并使用它们,分配就会运行,就像在这个样本中一样:

Console.WriteLine("press a key to allocate the memory");
Console.ReadKey();
double[] hudgeBunchOfMemory = new double[100000000];
for (long i = 0; i < 100000000; i++)
{
    hudgeBunchOfMemory[i] = i + 1;
}
Console.WriteLine("allocated");
Console.ReadKey();

是什么产生了这种行为?

修改

我已经在发布和调试模式下使用Visual Studio 2012破坏了代码,并且我已经使用任务管理器评论了内存更改,并且可以非常简单地观察差异,因为它需要800Mb的内存。

关于这种行为的最合适的问题是:代码是否已执行,内存是否仍然没有被占用,或者它根本没有被执行,并且被JIT编译器避免了?

1 个答案:

答案 0 :(得分:6)

您正在查看的统计信息(可能是在任务管理器中)是工作集。它测量您的进程使用的物理内存量。 RAM。

   double[] hudgeBunchOfMemory = new double[100000000];

在需求分页的虚拟内存操作系统(如Windows(或Linux或OSX))上,该语句分配RAM。 CLR充分利用了操作系统的虚拟内存功能,它分配了地址空间。只是处理器的编号,每4096字节的内存一个。

您实际上可以看到分配生效,您必须在任务管理器中添加一列才能看到它。使用视图&gt;选择列或右键单击列标题,然后选择&#34;提交大小&#34;。同时选择&#34; Page fault&#34;,提供更多洞察力。

现在您看到第一个代码段的区别了。按Enter键后,您会看到“提交大小”列跳转。 CLR已使用VirtualAlloc()分配地址空间并确保内存预留已提交,它还在页面文件中分配了800000000个字节。你看到工作集上升了一点,用于存储页表映射条目的RAM,用于存储那些每4096字节一个数字的数据。还有两页(8192字节)CLR有意加热,因为它会假设你先使用这些页面。

您现在还可以看到第二个代码段的效果。当你访问数组元素时,踏板需要满足金属,你需要分配RAM来存储数组元素。在非常低的级别,写入内存地址的指令会导致页面错误。这迫使操作系统实现 demand paged 功能,它必须分配物理内存。您现在可以看到工作集和页面错误计数器拉链。对于你来说,看到它们变化的速度可能太快,现代机器有很多RAM。它可能不是当操作系统必须争取获取RAM并将其从其他进程中取走时,硬页故障是昂贵的。

评论中有很多错误的猜测,应该加以解决。不,编译器和抖动都不会对此产生任何影响。这纯粹是操作系统行为。它在Debug和Release构建中的行为相同。即使你实际上并没有在第一个片段中使用该数组,正如您可以从提交大小计数器中看出的那样,会被抖动优化器消除。对于任何new语句都是保守的,并且总是假设它的副作用应该是可见的。