大文件 I/O 是否适合使用 mmap() 函数?

6
我正在使用C++创建一个在Linux上运行的实用程序,可以将视频转换为专有格式。视频帧非常大(高达16兆像素),我们需要能够直接跳转到精确的帧编号,因此我们的文件格式使用libz来压缩每个帧并将压缩数据附加到文件中。完成所有帧的写入后,会将包括每个帧元数据(包括它们的文件偏移量和大小)的日志写入文件末尾。
目前我正在使用ifstream和ofstream进行文件I/O,但我正在寻求尽可能多的优化。我听说mmap()可以在很多情况下提高性能,想知道我的情况是否适用。我们的文件将达到数十到数百GB,尽管写入始终是顺序进行的,但随机访问读取应该在恒定时间内完成。有没有人对我是否应该进一步调查这个问题有任何想法?如果有,有没有什么要注意的事项?
谢谢!

读取的随机程度有多大?范围是无限制的还是有限制的? - MSN
1
顺便说一句 - 即使您需要无损质量,那似乎也不是存储视频的好方法。 - slacker
1
懒人:在大多数情况下,我同意,但我们需要能够寻找精确的帧数(而不仅仅是最接近的I帧或任何这样的近似值,这是ffmpeg似乎能够使用其任何格式做到的最好的)。如果有一个快速的库/格式正好符合我的需求,那么我很想听听它的消息! - rcv
2
该格式称为M-JPEG,ffmpeg支持它。它实质上是一系列独立压缩的JPEG帧。 - slacker
啊,但我需要无损质量 - 事实上,我需要存储每个像素数据高达64位/通道,所以我不知道有哪种格式(甚至是MNG,它被限制在16位/通道)可以处理这个。 - rcv
显示剩余3条评论
2个回答

10

在32位机器上,您的进程被限制在2-3GB的用户地址空间内。这意味着(考虑到其他内存使用),您一次最多只能映射约1GB的文件。这不意味着您不能使用mmap()来处理非常大的文件 - 只是您需要一次映射部分文件。

也就是说,对于大文件,mmap()仍然可以提供很大的优势。最重要的优点是,您不会浪费内存来保留数据的两个副本 - 一个在系统缓存中,另一个在应用程序的私有缓冲区中 - 以及为进行这些复制所需的CPU时间。对于随机访问,它甚至可以更快速 - 但“随机”部分必须在当前映射范围内。


没错,我想的方法是在用户读取一帧时尽可能多地使用mmap映射内存,并从该映射中读取所需数据。 有人知道mmap()调用的开销如何与seek()相比吗? - rcv
@Boatzart: 它们是可比较的。这里的主要成本是内核调用和内核执行的映射。但是,对于seek()仍然需要执行这些操作。 - slacker
1
我建议一次只映射文件的较小部分,以避免浪费太多内存和地址空间。与处理数兆字节数据所需的时间相比,mmap() 调用的开销微不足道。 - slacker
1
请注意,您可以同时拥有单个文件的多个映射。 - slacker

7
如果您的文件大小达到10GB或更大,那么请不要尝试在32位体系结构上使用函数。直接升级到64位操作系统,应该就可以处理这个问题了。
需要注意的是,映射到内存空间中的文件实际上并不会消耗与文件大小相同的RAM(内存),因此您无需在计算机上安装数百GB的RAM。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接