如何扩大mmap()分配的内存区域且保留其起始地址与原有内容
结论
可以实现,使用Linux的mremap系统调用即可,该调用专门用于调整已存在mmap映射区域的大小,默认会保留原有内存区域的所有内容,也可以通过标志位要求内核保留原映射的起始地址。
ARM64架构下的实现说明
你当前使用的是ARM64指令集的系统调用规范,mremap的参数对应寄存器、调用方法如下:
调用参数说明
- x0:传入原有
mmap调用返回的内存区域起始地址(注意你必须提前保存好mmap调用成功后x0里的地址值) - x1:原有内存区域的大小,这里你之前分配的是4096,直接填入即可
- x2:调整后的新内存区域总大小,比如你要扩大到8KB就填入8192
- x3:控制标志:
- 填
MREMAP_MAYMOVE(值为1):允许内核在原地址后没有足够连续空间时,将整个映射迁移到其他地址,原有内容会完整保留,返回新的地址 - 填
MREMAP_MAYMOVE | MREMAP_FIXED(值为3):强制要求内核必须保留原起始地址,如果原地址后没有足够空间则直接调用失败
- 填
- x8:
mremap的ARM64系统调用号为223
示例汇编代码
; 假设之前mmap返回的起始地址已经存在x9寄存器里(你需要自行保存该值) mov x0, x9 ; 传入原映射起始地址 mov x1, 4096 ; 原有映射的大小 mov x2, 8192 ; 扩大后的总大小,示例为8KB mov x3, 1 ; MREMAP_MAYMOVE,允许必要时迁移地址 mov x8, 223 ; mremap系统调用号 svc 0 ; 调用结果判断:如果x0为负值,代表调用出错,错误码为-x0
注意事项
- 如果你强制要求保留原地址,需要确保原映射区域之后的连续虚拟地址空间没有被其他映射占用,否则
mremap会返回-ENOMEM错误 - 调用成功后,新的内存区域起始地址会返回在x0寄存器中,后续操作需要使用这个新地址(如果没有迁移的话就和你传入的原地址一致)
- 扩大后的内存区域新增的部分和原有匿名映射的规则一致,初始内容为0
内容的提问来源于stack exchange,提问作者Alexander Zhak
相关产品推荐
相关产品推荐

