mmap 是不是连续分配堆内存?

Posted

技术标签:

【中文标题】mmap 是不是连续分配堆内存?【英文标题】:Does mmap allocate heap memory contiguously?mmap 是否连续分配堆内存? 【发布时间】:2012-10-25 10:12:55 【问题描述】:

前提是:

我要求的尺寸是页面尺寸的倍数 我请求的起始地址是最后一次分配的大小+起始地址

如果我在使用 mmap 在堆上分配内存时始终遵循这些规则,返回的地址会是连续的吗?或者他们之间会不会有差距?

【问题讨论】:

在哪个操作系统中?这些东西取决于操作系统。 如果它不是独立于操作系统的,那么我假设我的问题的答案是“否”,因为我想编写可移植代码。 “便携”是一个非常宽泛的术语。 【参考方案1】:

您可以使用 MAP_FIXED 标志获得所需的行为。不幸的是,对于您的目标,它并未得到普遍支持,因此您需要检查返回值以确保它为您提供了您请求的分配。为了获得良好的可移植性,您需要在调用返回 0 时制定备份计划。

【讨论】:

【参考方案2】:

快速回答:不一定。在各种机器上进行有限的广泛测试时,它很有可能“几乎总是有效”,但这绝对不是一个好的做法。大多数 Linux 版本都支持 MAP_FIXED 标志,但根据我的经验,它也有问题。避免。

在您的情况下,最好一次性分配您需要的所有内容,然后手动将指针分配给映射的每个子部分:

int LengthOf_FirstThing = 0x18000;
int LengthOf_SecondThing = 0x10100;
int LengthOf_ThirdThing = 0x20000;

int _pagesize = getpagesize();
int _pagemask = _pagesize - 1;

size_t sizeOfEverything = LengthOf_FirstThing + LengthOf_SecondThing + LengthOf_ThirdThing;
sizeOfEverything = (sizeOfEverything + _pagemask) & ~(_pagemask);

int8_t* result = (int8_t*)mmap(nullptr, sizeOfEverything, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
int8_t* myFirstThing = result;
int8_t* mySecondThing = myFirstThing + LengthOf_FirstThing;
int8_t* myThirdThing = mySecondThing + LengthOf_SecondThing;

这种方法的一个优点还在于,您要映射的每一件事都不必与页面大小严格对齐。最重要的是,它确保了完全连续的内存。

更长的答案: mmap() 的实现可以完全无视“提示”地址,因此您永远不应该期望该地址得到尊重。这可能比预期的更常见,因为某些实现实际上可能不支持新 mmap() 的页面大小粒度。它们可能会将有效的起始映射限制为 16k 或 64k 边界,以帮助减少管理非常大的虚拟地址空间所需的开销。这样的实现总是会忽略未与此类边界对齐的 mmap() 提示。

此外,mmap() 根本不从堆中分配内存。堆是创建进程时由 C 运行时库(*nix 上的 glibc)创建/保留的内存区域。 malloc() 和 new/delete 通常是从堆中提取的唯一函数,以及可能在内部使用 malloc/new 的任何库。堆本身通常由内部调用 mmap() 创建和管理。

【讨论】:

【参考方案3】:

我认为这不是指定的,而是所谓的“实施细节”。 IE。您不应该依赖一种行为或另一种行为,而是假设指针是不透明的,并且不关心它的确切值。

(也就是说,可能会有黑客攻击的地点和时间。在这种情况下,您需要准确了解您的操作系统的行为方式。)

【讨论】:

以上是关于mmap 是不是连续分配堆内存?的主要内容,如果未能解决你的问题,请参考以下文章

进程环境详解---堆分配mallocfree函数详解

linux环境内存分配原理 mallocinfo

Linux 内核 内存管理内存管理架构 ④ ( 内存分配系统调用过程 | 用户层 malloc free | 系统调用层 brk mmap | 内核层 kmalloc | 内存管理流程 )

malloc的内存分配原理

Java 堆

[转]JVM堆和栈的区别