如何增加使用 mmap() 分配的内存区域的大小
How to increase the size of memory region allocated with mmap()
我正在使用 mmap
Linux 系统调用分配内存。
mov x5, 0 ; offset is zero
mov x4, -1 ; no file descriptor
mov x3, 0x22 ; MAP_PRIVATE + MAP_ANONYMOUS
mov x2, 3 ; PROT_READ + PROT_WRITE
mov x1, 4096 ; initial region size in bytes
mov x0, 0 ; let Linux choose region address
mov x8, 222 ; mmap
svc 0
是否可以在保留其起始地址和内容的情况下增加已分配内存区域的大小?如何正确操作?
如果您的原始区域后面有空闲虚拟地址 space,只需使用 MAP_FIXED | MAP_FIXED_NOREPLACE
标志和相同的权限在原始区域后面创建一个额外的映射区域。如果两个区域的页面大小相同,它们将合并为一个映射。
在 Linux 上,使用 mremap(2)
Linux 特定的系统调用 而无需 MREMAP_MAYMOVE
扩展现有映射,不考虑将这些物理页面重新映射到不同的虚拟地址的选项,其中有足够的空间用于更大的映射。
如果您要扩展到的页面已经存在一些其他映射,它将 return 出错。 (与 mmap(MAP_FIXED)
不同,它会默默地替换那些映射。)
如果您正在用 asm 编写,那么对非 Linux 的可移植性几乎无关紧要;其他操作系统将有不同的调用号和 ABI,因此只需在 asm/unistd.h
中查找 __NR_mremap
,然后从 sys/mman.h
.
中获取 flags
模式
仅可移植 POSIX 调用,mmap()
具有非 NULL 提示地址 = 就在现有映射之后,但没有 MAP_FIXED
;如果页面空闲,它将选择该地址(正如@datenwolf 所说,与早期映射合并到一个长范围内)。否则它会选择其他地方。 (然后你必须 munmap
最终不在你想要的位置的映射。)
有一个 Linux-特定的 mmap
选项:MAP_FIXED_NOREPLACE
将 return 一个错误,而不是映射到与提示不同的地址。早于 4.17 的内核不知道该标志,通常会将其视为除了 MAP_ANONYMOUS
之外没有使用其他标志,因此您应该根据提示检查 return 值。
不要使用MAP_FIXED_NOREPLACE | MAP_FIXED
;这将在旧内核上充当 MAP_FIXED
,也可能在知道 MAP_FIXED_NOREPLACE
.
的新内核上充当
假设您知道要扩展的映射的起点以及所需的新总大小,mremap
是比 mmap(MAP_FIXED_NOREPLACE)
更好的选择。它至少从 Linux 2.4 开始支持,即几十年,并自动保留现有的映射标志和权限(例如 MAP_PRIVATE、PROT_READ|PROT_WRITE)
如果你只知道现有映射的结束地址,mmap(MAP_FIXED_NOREPLACE)
可能是个不错的选择。
我正在使用 mmap
Linux 系统调用分配内存。
mov x5, 0 ; offset is zero
mov x4, -1 ; no file descriptor
mov x3, 0x22 ; MAP_PRIVATE + MAP_ANONYMOUS
mov x2, 3 ; PROT_READ + PROT_WRITE
mov x1, 4096 ; initial region size in bytes
mov x0, 0 ; let Linux choose region address
mov x8, 222 ; mmap
svc 0
是否可以在保留其起始地址和内容的情况下增加已分配内存区域的大小?如何正确操作?
如果您的原始区域后面有空闲虚拟地址 space,只需使用 MAP_FIXED | MAP_FIXED_NOREPLACE
标志和相同的权限在原始区域后面创建一个额外的映射区域。如果两个区域的页面大小相同,它们将合并为一个映射。
在 Linux 上,使用 mremap(2)
Linux 特定的系统调用 而无需 MREMAP_MAYMOVE
扩展现有映射,不考虑将这些物理页面重新映射到不同的虚拟地址的选项,其中有足够的空间用于更大的映射。
如果您要扩展到的页面已经存在一些其他映射,它将 return 出错。 (与 mmap(MAP_FIXED)
不同,它会默默地替换那些映射。)
如果您正在用 asm 编写,那么对非 Linux 的可移植性几乎无关紧要;其他操作系统将有不同的调用号和 ABI,因此只需在 asm/unistd.h
中查找 __NR_mremap
,然后从 sys/mman.h
.
flags
模式
仅可移植 POSIX 调用,mmap()
具有非 NULL 提示地址 = 就在现有映射之后,但没有 MAP_FIXED
;如果页面空闲,它将选择该地址(正如@datenwolf 所说,与早期映射合并到一个长范围内)。否则它会选择其他地方。 (然后你必须 munmap
最终不在你想要的位置的映射。)
有一个 Linux-特定的 mmap
选项:MAP_FIXED_NOREPLACE
将 return 一个错误,而不是映射到与提示不同的地址。早于 4.17 的内核不知道该标志,通常会将其视为除了 MAP_ANONYMOUS
之外没有使用其他标志,因此您应该根据提示检查 return 值。
不要使用MAP_FIXED_NOREPLACE | MAP_FIXED
;这将在旧内核上充当 MAP_FIXED
,也可能在知道 MAP_FIXED_NOREPLACE
.
假设您知道要扩展的映射的起点以及所需的新总大小,mremap
是比 mmap(MAP_FIXED_NOREPLACE)
更好的选择。它至少从 Linux 2.4 开始支持,即几十年,并自动保留现有的映射标志和权限(例如 MAP_PRIVATE、PROT_READ|PROT_WRITE)
如果你只知道现有映射的结束地址,mmap(MAP_FIXED_NOREPLACE)
可能是个不错的选择。