C中的别名内存
Alias memory in C
如果我有像这样的绳状数据结构:
struct rope {
struct { char *buf; size_t len; } *segments;
size_t len;
}
有没有办法将每个段的缓冲区连续映射到虚拟内存中 space,而无需复制?我的用例是以最有效的方式将绳索转换为字符串。
这是一个如何使用它的例子:
char *s = rope_flatten(r);
printf("%s\n", s);
r.segments[0].buf[4] = 'x';
printf("%s\n", s); // The 5th character is now replaced with 'x'
不用说,缓冲区(至少,映射的位)不会以 NUL 终止。
我知道这可能非常特定于平台。如果有符合 POSIX 的东西那就太棒了。如果没有,Linux 是我的主要目标,如果不支持,我可以回退到 malloc 和 memcpy。
在一个完美的世界中,您可以像往常一样创建您的绳索并再次重新映射每个段,这样您就可以看到它们是连续的第二个视图。如果您编辑一个片段,没问题,它会镜像到另一个视图。如果你放大一个段,缓冲区会透明地更新。
尽管有几个问题使这不可行:
- 虚拟内存的粒度不是按字节而是按页,通常为 4KiB,并且它们被映射为一个整体。您的代码单元可能比那个小一点。
- 添加和删除段仍需要页面 table 修改
- 修改时必须调用内核来更新映射,这很容易使您希望获得的任何性能优势相形见绌。
- 可移植性问题:API 是 OS 特定的。需要 MMU。与 VIVT 缓存结合使用时的有趣效果
尽管如此,仍有将多个视图映射到一个地址的用例space,即当数据发生变化但数据未发生变化时结构,就像环形缓冲区一样:
通常情况下,您必须在软件中实现环绕逻辑,但如果您之后直接重新映射环形缓冲区的页面,您将获得一个环形缓冲区,您可以 memcpy
. GNU Radio 采用了这种机制,并且有一个不错的博客 post:
https://www.gnuradio.org/blog/buffers/
博客 post 让我很好奇,所以我在 libvas 中重新实现了 Linux、Windows 和 macOS 的机制。喜欢的可以看看
如果我有像这样的绳状数据结构:
struct rope {
struct { char *buf; size_t len; } *segments;
size_t len;
}
有没有办法将每个段的缓冲区连续映射到虚拟内存中 space,而无需复制?我的用例是以最有效的方式将绳索转换为字符串。
这是一个如何使用它的例子:
char *s = rope_flatten(r);
printf("%s\n", s);
r.segments[0].buf[4] = 'x';
printf("%s\n", s); // The 5th character is now replaced with 'x'
不用说,缓冲区(至少,映射的位)不会以 NUL 终止。
我知道这可能非常特定于平台。如果有符合 POSIX 的东西那就太棒了。如果没有,Linux 是我的主要目标,如果不支持,我可以回退到 malloc 和 memcpy。
在一个完美的世界中,您可以像往常一样创建您的绳索并再次重新映射每个段,这样您就可以看到它们是连续的第二个视图。如果您编辑一个片段,没问题,它会镜像到另一个视图。如果你放大一个段,缓冲区会透明地更新。
尽管有几个问题使这不可行:
- 虚拟内存的粒度不是按字节而是按页,通常为 4KiB,并且它们被映射为一个整体。您的代码单元可能比那个小一点。
- 添加和删除段仍需要页面 table 修改
- 修改时必须调用内核来更新映射,这很容易使您希望获得的任何性能优势相形见绌。
- 可移植性问题:API 是 OS 特定的。需要 MMU。与 VIVT 缓存结合使用时的有趣效果
尽管如此,仍有将多个视图映射到一个地址的用例space,即当数据发生变化但数据未发生变化时结构,就像环形缓冲区一样:
通常情况下,您必须在软件中实现环绕逻辑,但如果您之后直接重新映射环形缓冲区的页面,您将获得一个环形缓冲区,您可以 memcpy
. GNU Radio 采用了这种机制,并且有一个不错的博客 post:
https://www.gnuradio.org/blog/buffers/
博客 post 让我很好奇,所以我在 libvas 中重新实现了 Linux、Windows 和 macOS 的机制。喜欢的可以看看