我注意到了这种奇怪的效果,在触摸内存之前,内存不会被注册为Windows任务管理器分配的内存,而不是malloc
-ed或new
-ed。该效应发生在debug
和优化的release
构建中。
下面是一个结构示例,尽管在我的代码中,分配和利用率发生在不同的线程上,所以我不认为它是优化器,尽管我不确定如何检查。
for (int i = 0 ;i < 1000;i++)
{
buffer[i]=malloc(buffersize);
}
_sleep(1000*60)
for (int i=0;i<1000;i++)
{
memset(buffer[i],0,buffersize);//Only shows up the in the resource manager here
}
我的问题是Windows如何知道我已经使用了内存?它是监视内存的首次使用,还是一些编译时优化。
我的好奇心来自于我正在写的一个实时采集,它要求我在分配时触摸内存两次->一次,在实际填充数据时触摸内存一次。因此,按下一个按钮("aqure!"(需要我一次写入64G的ram,而不是随着时间的推移,这会增加相当实际的延迟。如果我边走边malloc
,这会增加太多延迟。
--编辑--
我还禁用了Windows页面文件。。。
这是像Windows这样的需求页虚拟内存操作系统的标准行为。malloc((调用只分配虚拟内存地址空间。直到访问内存,您才真正开始使用RAM。这会产生页面错误,迫使操作系统将您访问的内存页面映射到RAM中。
这通常是一个软页面故障,通过从空闲列表中抓取一个RAM页面并映射它来快速处理。与硬页面故障相反,当一些RAM页面再次交换到交换文件时,你会遇到这种故障,因为另一个进程需要RAM。从磁盘重新加载页面需要更多时间。
禁用分页文件有助于避免那些硬分页错误。这并不能消除它们,你的代码页也会被交换掉。当你强迫操作系统回到它们的时候,很可能会发生这种情况,因为它不能再交换到页面文件了。这样的页面在换出时会被丢弃,当页面出现故障时会从可执行文件中重新加载。
如果您有软实时需求,那么最好的策略是尽早分配内存,并在开始承诺快速响应之前有意访问内存。可以简单地使用calloc((而不是malloc((来完成。
分配给进程的虚拟地址空间不一定由物理RAM支持。一个例子是分页文件,如果物理RAM不足,则使用中的内存可能会移动到其中。但是,如果你从未写入过任何物理RAM或磁盘空间,那么就不必分配任何物理RAM和磁盘空间。因此,作为一种优化,一些操作系统会给你虚拟地址空间,而实际上还没有为它分配空间。在某些情况下,这是非常有益的。在其他情况下,就像你的情况一样,这有点烦人。
也就是说,任务管理器是一个用于调查内存使用情况的非常简单的工具。幸运的是,你能够观察到这一点,许多问题不能(可靠地(只使用任务管理器来观察。
至于如何在不影响所有内存的情况下避免延迟分配。。。我不知道有什么办法。即使是VirtualAlloc
也没有提供解决这一问题的方法。您可以通过每页只写一个字节来稍微降低成本,这仍然会导致物理RAM分配。但请记住,即使您可以避免写入任何内容,Windows仍必须分配1600万个页面,包括页面表条目。这肯定需要一些时间。您可以使用大页面(使用VirtualAlloc
(,这会使页面大几百倍,从而将前面提到的1600万页面减少到一个更合理的数字。
您的操作系统似乎在懒散地分配内存。查看此问题的答案
基本上,当您调用malloc时,操作系统会给您的程序一个地址,并承诺按请求的数量提供内存。我读到的类比是,操作系统为内存"写一张支票",但只有当你的程序试图用它"兑现"支票时,才分配物理内存。
我认为,如果你想在malloc
时把延迟命中率放在前面,你应该在那里memset
。
您可以同时尝试malloc
并立即为其分配一个空值,以克服NicholasM所说的"懒惰内存分配"。即便如此,编译器也可能会发现您正在赋值,但没有使用赋值,并将其从编译的代码中删除。但别忘了操作系统为什么懒洋洋地分配内存。