C 如何实现或模拟MADV_ZERO?

C 如何实现或模拟MADV_ZERO?,c,linux,shared-memory,mmap,fallocate,C,Linux,Shared Memory,Mmap,Fallocate,我希望能够在不调用任何io的情况下将文件内存映射的范围归零(以便高效地按顺序覆盖巨大的文件,而不会产生任何磁盘读取io) 执行std::memset(ptr,0,length)将导致从磁盘读取页面(如果页面尚未在内存中),即使整个页面被覆盖,也会完全破坏磁盘性能 我希望能够执行类似于madvise(ptr,length,MADV_ZERO)的操作,在访问指定范围时,将该范围归零(类似于),从而导致零填充页面错误,而不是常规io页面错误 不幸的是,MADV_ZERO不存在。即使相应的标志确实存在于

我希望能够在不调用任何io的情况下将文件内存映射的范围归零(以便高效地按顺序覆盖巨大的文件,而不会产生任何磁盘读取io)

执行
std::memset(ptr,0,length)
将导致从磁盘读取页面(如果页面尚未在内存中),即使整个页面被覆盖,也会完全破坏磁盘性能

我希望能够执行类似于
madvise(ptr,length,MADV_ZERO)
的操作,在访问指定范围时,将该范围归零(类似于),从而导致零填充页面错误,而不是常规io页面错误

不幸的是,
MADV_ZERO
不存在。即使相应的标志确实存在于中,并且可以与
fwrite
一起使用,以实现类似的效果,但没有即时的跨进程一致性

我想一个可能的选择是使用。然而,据我所知,这可能会导致文件碎片,并在完成时阻止其他操作,这使我无法确定其长期性能影响。我对Windows的经验是,类似的命令在调用时可能会导致显著的性能峰值

我的问题是如何实现或模拟共享映射的
MADV_ZERO
,最好是在用户模式下

1.
/dev/zero/
我已经读到了只需将
/dev/zero
读入所选的范围
。虽然我不太清楚“读入范围”是什么意思以及如何做到这一点。它是否像从
/dev/zero
进入内存范围的
fread
?不确定如何避免访问时出现常规页面错误

对于Linux,只需将
/dev/zero
读入所选范围即可。这个 内核已经为匿名映射优化了这种情况

如果一般来说执行起来太难,我
建议MADV_ZERO应具有以下效果:与阅读完全相同
/dev/zero进入范围,但始终有效

编辑:跟随线程一点,结果是它实际上不会工作

在处理共享映射时,它不起作用

2.
MADV\u删除
在Linux中实现它的一个猜测(即不是在用户应用程序中,这是我更喜欢的)可能是简单地复制和修改
MADV_REMOVE
,即使用而不是。虽然我猜得有点过头了,尤其是当我不太明白
vfs\u allocate
周围的代码在做什么时:

// madvice.c
static long madvise_remove(...)
  ...
  /*
   * Filesystem's fallocate may need to take i_mutex.  We need to
   * explicitly grab a reference because the vma (and hence the
   * vma's reference to the file) can go away as soon as we drop
   * mmap_sem.
   */
  get_file(f); // Increment ref count.
  up_read(&current->mm->mmap_sem); // Release a read lock? Why?
  error = vfs_fallocate(f,
            FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, // FALLOC_FL_ZERO_RANGE?
            offset, end - start);
  fput(f); // Decrement ref count.
  down_read(&current->mm->mmap_sem); // Acquire read lock. Why?
  return error;
}

您可能无法做您想做的事情(在用户空间中,不攻击内核)。请注意,写入零页可能不会导致物理磁盘IO,因为


您可能希望在中用文件孔替换文件段(但这并不完全是您想要的),但某些文件系统(例如VFAT)没有孔或稀疏文件。请参见
SEEK\u HOLE

很可能“简单地将
/dev/zero
读入所选范围”指的是。@code艺术家:不太确定从中得到什么…从
flags=MAP\u ANONYMOUS | MAP\u SHARED | MAP\u NORESERVE
开始,然后沿着代码路径直到
shmem\u zero\u setup()
查看完整图片。对于匿名映射,在没有支持零页的文件的情况下,最初使用零页来优化读取。当然,这并不能解决你的问题。这只是一个适当实现的示例,如果您想自己在内核中实现建议,可以参考它。另一方面,如果您要将固定模式的块写入磁盘(即长序列的零),为什么不在
O|u DIRECT | O|WRONLY
lseek()中打开文件
到适当的偏移量,只需转储大数据块(磁盘块大小的倍数),直到
len
字节数归零。显然是这个。你觉得呢?…坚持不懈的IPC让我想起了过去的美好回忆。我在玩mmap ed文件,目的完全相同。我使用inotify监视文件支持的“共享内存”。因为没有P在我的设计中,writer线程将更新内存映射共享文件中的所有相关字段,并最终触发一个
msync()
,在此基础上,使用inotify等待的读卡器线程将被解锁。我希望它能有所帮助……是的,这就是
MADV_REMOVE
的作用。但是,正如我们都注意到的,它会导致文件变得稀疏,并且在完成时打孔会将文件从所有其他操作中锁定(例如,Windows非常慢,到目前为止还没有在Linux上测试)。这让我怀疑它对长期绩效的影响。我需要的用例是24/7写入,没有任何时间进行碎片整理。我相信您在文件/页面缓存方面也有同样的问题。因为页面缓存本身使用内存映射的部分,但是在更大的边界上。不过我不确定。