2012-11-05 82 views
2

前提是:mmap是否连续分配堆内存?

  • 大小我请求的页面大小
  • 起始地址我要求的倍数的大小+启动最后一个分配

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

+1

在哪个操作系统?这些东西取决于操作系统。 –

+0

如果它不是独立于操作系统的,那么我假设我的问题的答案是“否”,因为我想编写可移植代码。 – Matt

+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运行时库(glibc on * nix)创建/保留的内存区域。 malloc()和new/delete通常是从堆中提取的唯一函数,以及任何可能在内部使用malloc/new的库。堆本身通常由内部调用mmap()来创建和管理。

1

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

(这就是说,有可能是黑客的地方和时间。在这种情况下,你需要找出你的操作系统究竟如何运行。)

3

你可以得到你想要用MAP_FIXED标志的行为。不幸的是,对于你的目标,这不是普遍支持,所以你想检查返回值,以确保它给你你请求的分配。为了便于携带,您需要一个备份计划,以便在通话返回0时返回0.