我编写了一个 WPF 应用程序,面向 .NET 4.5.2 64 位。它在 Windows 8.1 Professional 64 位上运行。
该应用程序用于同时录制多个视频。由于视频编码器的速度在运行过程中可能会有很大差异,因此我在内存中创建了一些非常大的字节数组(总共 6 GiB),这足以让我缓冲 40 秒的视频,并且我让编码在单独的线程上进行,因此我不会冒被编码阻止并错过来自摄像机的传入帧的风险。
我在某处读到(字节)数组在 .NET 中是延迟分配的 - 即只写 byte[] foo = new byte[1024*1024];
并不意味着立即分配 1 MiB;直到第一次访问时才真正分配内存。虽然我再也找不到在哪里读过那句话了。无论如何,知道这一点,我一定要调用Array.Clear()
在我的数组上,这应该强制它们立即分配。我还需要确保缓冲区始终保留在 RAM 中,因此我完全禁用了页面文件。
但由于某种原因,.NET 运行时或 Windows 似乎仍在做一些疯狂的事情:在初始化我的字节数组并对所有字节数组调用 Array.Clear() 之后,我可以在任务管理器中看到 7.4 GiB 正在使用中。它就坐在那里直到我按下“记录”按钮,此时我开始有真实的数据来填充缓冲区。奇怪的是,In Use 内存开始下降到 3.6 GiB 左右,然后又慢慢回升到 7.4 GiB。我的应用程序从来没有丢弃和重新分配数组。另请记住,由于我已禁用页面文件,因此 Windows 没有地方可以调出页面。
这是怎么回事?我该如何解释这种奇怪的现象?
最佳答案
What is going on? How should I interpret this weirdness?
这并不奇怪,这就是垃圾收集的工作原理。
当您使用Array.Clear
时,您只是将这些字节重置为0(感谢@Martin)。 这并不意味着垃圾收集将在同一时刻发生。如果该数组仍然被引用,则这甚至不会使其符合收集条件。 GC 的运行时间是不确定的。
您所看到的实际上是有道理的,因为您看到一旦您按下“记录”,运行时需要分配更多资源来使用,它首先调用一个集合,然后随着这些字节的消耗而开始缓慢增加通过您的应用程序。
正如其他人在评论中所说,如果您需要对应用程序中管理的内存进行细粒度的粒度,那么您最好使用较低级别的语言,这样您就可以(尽可能地)控制内存的分配和释放内存。
关于.net - .NET 中奇怪的数组内存管理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34174495/