我写了关于fwrite VS mmap( “衡量传统I / O与内存映射文件之间的性能折衷的实验”)
的比较学士学位论文。首先,对于写入,您不必去寻找内存映射文件,尤其是大文件。
fwrite是完全可以的,并且几乎总是会优于使用
mmap。
mmap将为您提供最大的并行数据读取性能提升;用于连续数据写入的真正限制
fwrite是硬件。
在我的示例中,
remapSize是文件的初始大小以及每次重新映射时文件增加的大小。
fileSize跟踪文件
mappedSpace的大小,表示当前mmap的大小(它的长度),
alreadyWrittenBytes是已经写入文件的字节。
这是示例初始化:
void init() { fileDescriptor = open(outputPath, O_RDWR | O_CREAT | O_TRUNC, (mode_t) 0600); // Open file result = ftruncate(fileDescriptor, remapSize); // Init size fsync(fileDescriptor); // Flush memoryMappedFile = (char*) mmap64(0, remapSize, PROT_WRITE, MAP_SHARED, fileDescriptor, 0); // Create mmap fileSize = remapSize; // Store mapped size mappedSpace = remapSize; // Store mapped size}广告Q1:
我使用了“取消映射-重新映射”机制。
取消映射
- 第一次冲洗(
msync
) - 然后取消映射内存映射的文件。
这看起来可能如下:
void unmap() { msync(memoryMappedFile, mappedSpace, MS_SYNC); // Flush munmap(memoryMappedFile, mappedSpace)}对于 Remap ,您可以选择重新映射整个文件或仅重新映射新添加的部分。
基本上重新映射
- 增加文件大小
- 创建新的内存映射
完整重映射的示例实现:
void fullRemap() { ftruncate(fileDescriptor, mappedSpace + remapSize); // Make file bigger fsync(fileDescriptor); // Flush file memoryMappedFile = (char*) mmap64(0, mappedSpace + remapSize, PROT_WRITE, MAP_SHARED, fileDescriptor, 0); // Create new mapping on the bigger file fileSize += reampSize; mappedSpace += remapSize; // Set mappedSpace to new size}小重新映射的示例实现:
void smallRemap() { ftruncate(fileDescriptor, fileSize + remapSize); // Make file bigger fsync(fileDescriptor); // Flush file remapAt = alreadyWrittenBytes % pageSize == 0 ? alreadyWrittenBytes : alreadyWrittenBytes - (alreadyWrittenBytes % pageSize); // Adjust remap location to pagesize memoryMappedFile = (char*) mmap64(0, fileSize + remapSize - remapAt, PROT_WRITE, MAP_SHARED, fileDescriptor, remapAt); // Create memory-map fileSize += remapSize; mappedSpace = fileSize - remapAt;}有一个
mremap function外面,但它指出
该调用是特定于Linux的,不应在旨在可移植的程序中使用。
广告Q2:
我不确定我是否明白这一点。如果您想告诉内核“现在加载下一页”,则不行,这是不可能的(至少据我所知)。但是请参阅 广告第3步 ,了解如何建议内核。
广告Q3:
您可以
madvise与flag一起使用
MADV_SEQUENTIAL,但请记住,这不会强制内核提前读取,而只是建议您这样做。
男子摘录:
这 可能会 导致内核主动预读
个人结论:
请勿
mmap用于顺序数据写入。与使用编写简单的算法相比,它只会导致更多的开销,并且会导致更多的“非自然”代码
fwrite。
使用
mmap随机访问读取大型文件。
这也是我论文期间获得的结果。通过使用
mmap顺序写入,我无法实现任何提速,实际上,这样做总是较慢。



