在我的建模代码中,我使用boost memory mapped files在磁盘上分配大型数组。
它运行良好,但我找不到一种方法来检测我分配的数据大于磁盘驱动器上的可用空间的情况。例如,以下代码将愉快地执行(假设我在HDD上的可用空间少于8E9字节):
boost::iostreams::mapped_file_params file_params;
file_params.path = path;
file_params.mode = std::ios::in | std::ios::out;
file_params.new_file_size = static_cast<size_t>(8E9); # About 10GB
file_params.length = static_cast<size_t>(8E9);
boost::iostreams::mapped_file result;
result.open(file_params);
我甚至可以在resuld.data()
上工作,直到我写入未分配的内存部分(因为HDD上缺少空间),然后我收到以下错误:
memory access violation at address: 0x7e9e2cd1e000: non-existent physical address
在我变得神秘memory access violation
之前,有没有办法检测到这个错误?
我实际测试了这个:如果文件比分区上的可用空间大,那么代码就会有内存访问冲突,如果它的代码更小(我通过更改分区上的空间而不是通过编辑代码来测试它)。
可能的解决方案
如果我std:fill
文件内容为零,我仍然得到memory access violation
,但此错误位于分配附近,更容易调试。我宁愿想办法提出异常。
答案 0 :(得分:1)
在我获得神秘内存访问冲突之前,有没有办法检测此错误?
当您只更改文件大小时,它将为sparse
,这意味着没有数据的区域不会占用磁盘空间。在写入期间分配空间 - 并且可以创建磁盘空间错误。
解决问题的方法是将(虚拟)数据写入文件,而不是仅仅更改大小。这需要更多的时间,但是你只能在第一个写周期中获得磁盘空间,因为文件后面有最终的大小。
答案 1 :(得分:1)
您可以使用fallocate
或posix_fallocate
预先为文件预留空间。这样你知道你不会“过度提交”。它在初始创建时具有性能缺陷。
出于安全原因,操作系统可能会将fallocate
上的块清零。
fallocate
允许您执行未写入的扩展区,但在首次访问时它仍然为零。
在Windows上,可以使用SetFileValidData
来对抗,甚至可以绕过它。
请注意,使用O_DIRECT
+ fallocate()
的Linux仍然使用相当大的CPU(而不是Windows SetFileValidData
),虽然IO带宽通常是瓶颈,但这仍然可能会引起注意如果你在同一时间做很多CPU工作,效果会很好。