使用boost::iostreams::mapped_file

3

我对内存映射非常陌生,正在尝试理解内存映射文件以在我的项目(基于Linux)中使用它们。 我的要求是从内存映射文件中写入并读取数据。 我编写了一个示例程序,只进行了写入操作,并且它可以正常工作,但是我有一些非常基本的疑问,因为我不太理解这个内存映射的原理。

#include <unordered_map>
#include <boost/iostreams/device/mapped_file.hpp>
using namespace boost::interprocess;
using namespace std;
typedef unordered_map<int, string> work;
int main()
{
        boost::iostreams::mapped_file_params  params;
        params.path = "map.dat";
        params.new_file_size = 100;
        params.mode = (std::ios_base::out | std::ios_base::in);
        boost::iostreams::mapped_file  mf;
        mf.open(params);
        work w1;
        w1[0] = "abcd";
        w1[1] = "bcde";
        w1[2] = "cdef";

        work* w = static_cast<work*>((void*)mf.data());
        *w = w1;
        mf.close();
        return 0;
}

我有几个问题:

  1. 当我执行mf.open(params)时,我发现磁盘上创建了一个大小为100的文件。 现在当我写入它即*w = w1,磁盘上的文件内容会发生改变。 这是否意味着我根本没有使用RAM,直接写入磁盘?

  2. 当我执行mf.size()时,它总是给我输入的大小作为实际创建的文件大小。我怎样才能找出我实际写入内存映射文件的数据大小?

  3. 如果我设置params.new_file_size = 10GB,则会在磁盘上创建一个该大小的文件,但不占用任何磁盘空间,通过使用df cmd进行确认。为什么会这样? -rwx------. 1 root root 10000000000 Apr 29 14:26 map.dat

  4. 我读到close file会释放映射。这是否意味着我在关闭后失去了所有写入的数据?但这并不正确,因为我有可行的代码,在关闭并重新打开文件后可以正确读取。

  5. 如何删除使用后创建的内存映射文件?通过使用rm -rf cmd/linux apis吗?

1个回答

4
当我执行 mf.open(params) 时,我看到磁盘上创建了一个大小为100的文件。现在,当我写入它即*w = w1时,磁盘上文件的内容会改变。这是否意味着我根本没有使用RAM,而是直接写入磁盘? 您正在使用内存映射文件。这意味着:您正在写入已映射到进程空间的“虚拟内存页面”,但实际上是指向磁盘块。增长表示页面在写入时被提交。
当我执行mf.size()时,它总是给我提供了我作为创建实际文件的输入的大小。如何找出我实际写入内存映射文件的数据大小? 您无法找到。您只能使用像stat这样的工具找到提交的块数。
如果我给出params.new_file_size = 10GB,那么会在磁盘上创建该大小的文件,但不会占用任何磁盘空间。通过使用df cmd进行确认。为什么?-rwx------。1 root root 10000000000 Apr 29 14:26 map.dat
它是稀疏分配的。例如,使用fallocate或其他平台上相似的操作。
我读到关闭文件会释放映射。这是否意味着关闭后我失去了所有写入的数据?但这不是真的,因为我有工作代码,其中我关闭文件,然后再次打开文件并正确读取它。
不是。这意味着映射已被释放。也就是说,进程空间中的/虚拟内存/区域现在“空闲”以供其他用途使用。
如何删除使用后创建的内存映射文件?通过使用rm -rf cmd / linux apis?

1
感谢您的回答。 因此,结合第一个答案和第四个答案,我得出结论,如果我不使用close,则实际上同时使用虚拟内存和磁盘空间。我的确切用例如下: 现在我没有使用内存映射的实现方式,我在内存中收集了10GB的数据(来自某些数据源),然后将其提供给avro文件编写器来编写avro文件。 每当我从某个数据源收集10GB的数据时,我就会这样做。 - Neha
现在,通过使用内存映射,我计划将这10GB的数据映射到一个文件中,并允许avro writer进行写入。在我贴出的示例中,就像将*w传递给writer一样。但是根据您的答案,如果我这样做,那么我仍然会使用内存,这是不好的。因此,我应该将数据写入内存映射文件中,关闭它,要求writer打开该文件并读取并使用它来编写avro文件。 我的理解正确吗? - Neha
你正在使用虚拟内存。你知道的。虚拟,就是指:不是物理的。这没关系。它使用“地址空间”。但地址空间很便宜。在64位系统上,你不会轻易用完地址空间。最近我成功地映射了200GiB的文件到内存中。 - sehe
(注意:操作系统有责任按需将页面读入内存。当没有足够的物理内存时,最近未使用的页面将被丢弃,因此如果您循环遍历整个内存区域,则最终会多次从磁盘读回相同的页面,除非所有内容都保留在内存中。) - sehe
@NehaRawat 你的意思是,“还有一个问题” :) 而且你不能用其他方式!虽然映射内存一次性映射整个区域,但它全部都是虚拟的(注意口诀?把它记在你的系统里!)。只有当你访问w[0]或w[8836752]时,相关页面才会被加载到内存中。 - sehe
显示剩余2条评论

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