shm_open()
函数- 使用预定义大的
length
参数调用mmap()
函数 - 多次调用
fork()
函数 - 可以任意调用
ftruncate()
函数
这样做的目的是确保由fork()
函数生成的每个进程都有一个共享段在相同的地址上。然而,我不想一直占用内存,而是动态调整大小(大小范围为0 - 大length
)。
这样做可行吗?会出现未定义行为吗?
shm_open()
函数length
参数调用mmap()
函数fork()
函数ftruncate()
函数这样做的目的是确保由fork()
函数生成的每个进程都有一个共享段在相同的地址上。然而,我不想一直占用内存,而是动态调整大小(大小范围为0 - 大length
)。
这样做可行吗?会出现未定义行为吗?
SIGBUS
信号。因此,您需要非常小心,不要触及当前文件长度之外的内存(或者捕获 SIGBUS
并处理它)。man 2 mmap
:
使用映射区域可能导致以下信号:
SIGBUS
尝试访问与文件不对应的缓冲区一部分(例如超出文件末尾的情况,包括另一个进程截断文件的情况)。
不要调整它的大小。
我不想一直占用内存
这就是内核使用虚拟内存为您完成的工作。只要您不使用 mlock()
或 MAP_LOCKED
,它将根据需要/适当地进行分页。
madvise()
,但要注意行为没有保证。 - Brian CainMADV_REMOVE
。但是如果我需要那些空间,我该怎么办? - Lorenzo PistoneMADV_DONTNEED
。 - Brian Cain创建任意大小的映射,除非您实际使用它,否则它不会“占用RAM”。
如果您担心在使用完RAM后仍然保持其繁忙状态,请调用madvise(MADV_DONTNEED)
- 这将清除页面并在再次访问时从零池中返回新页面。
MADV_DONTNEED
将丢弃页面并在需要时透明地从磁盘重新加载页面(如果由文件支持),或者(匿名映射)只是向您抛出一个零页面。请注意,后者实际上是“不正确”的行为,因为POSIX规定语义不会改变(这是相当明确的!)。但这正是你想要的。 - Damon
munmap
可能会触发对脏页的写入,从而引发SIGBUS
信号。 - Brian Cainmmap
范围的中间卸载页面)。 - Lorenzo Pistoneftruncate
之后进行mremap
以更新映射。尽管如此,您仍应最初分配大尺寸以防止mremap
因ENOMEM
而失败。 - jleahymremap
,但访问文件末尾之后的内存可能会导致崩溃。在实践中,使用mremap
更安全。 - nneonneo