簡體   English   中英

連續mmap調用永遠不會返回連續地址

[英]Consecutive mmap call never return contiguous address

函數page_allocate起作用。 它確實將地址返回到具有指定對齊方式的映射頁面。 但是,使用64k和1024k的連續調用永遠不會是連續的。 為什么?

  • ./mmap 0x00001000 // 4k
  • ./mmap 0x00002000 // 8k
  • ./mmap 0x00004000 // 16k
  • ./mmap 0x00008000 // 32k
  • ./mmap 0x00010000 // 64k錯誤? 無法獲得連續分配內的連續范圍
  • ./mmap 0x00020000 // 128k
  • ./mmap 0x00040000 // 256k
  • ./mmap 0x00080000 // 512k
  • ./mmap 0x00100000 // 1024k錯誤?
  • ./mmap 0x00200000 // 2048k
  • ./mmap 0x00400000 // 4096k
  • ./mmap 0x00800000 // 8192k
  • ./mmap 0x01000000 // 16384k
  • ./mmap 0x10000000 // 256Mb
  • ./mmap 0x100000000 // 4096mb

這里包括一個示例程序。 使用gcc -Wall -g mmap.c -o mmap進行編譯。

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#define _GNU_SOURCE /* MAP_ANONYMOUS */
#include <sys/mman.h>
#include <unistd.h> /* sysconf */

static size_t sys_page_size = 0;

void
page_init(void)
{
    int sc;

    if(!sys_page_size)
    {
        sc = sysconf(_SC_PAGESIZE);
        if(sc == -1)
        {
            sys_page_size = 0x0000000000001000; /* Default to 4Kb */
        }
        else
        {
            sys_page_size = sc;
        }
    }
}


void *
page_allocate(size_t request,
              size_t alignment)
{
    size_t size;
    size_t slop;
    void  *addr;

    /* Round up to page size multiple.
    */
    request   = (request   + (sys_page_size - 1)) & ~(sys_page_size -1);
    alignment = (alignment + (sys_page_size - 1)) & ~(sys_page_size -1);

    size      = request + alignment;


    /* Maybe we get lucky.
    */
    addr      = mmap(NULL,
                     request,
                     PROT_READ|PROT_WRITE,
                     MAP_PRIVATE|MAP_ANONYMOUS,
                     -1,
                     0);

    if(!((uintptr_t)addr & (alignment - 1)))
    {
        return addr;
    }
    munmap(addr, request);



    addr      = mmap(NULL,
                     size,
                     PROT_READ|PROT_WRITE,
                     MAP_PRIVATE|MAP_ANONYMOUS,
                     -1,
                     0);
    slop      = (uintptr_t)addr & (request - 1);


    #define POINTER_OFFSET(addr, offset) ((void *)((uintptr_t)(addr) + (offset)))
    if(slop)
    {
        munmap(addr, request - slop);
        munmap(POINTER_OFFSET(addr, size - slop), slop);
        addr = POINTER_OFFSET(addr, request - slop);
    }
    else
    {
        munmap(POINTER_OFFSET(addr, request), request);
    }


    return addr;
}

int
main(int    argc,
     char **argv)
{
    size_t size;

    void *cmp = NULL;
    void *ptr[16];
    int   i;

    page_init();


    if(argc == 2)
    {
        size = strtol(argv[1], NULL, 16);
    }
    else
    {
        size = 0x00001000;
    }


    for(i = 0;
        i < 16;
        i ++)
    { 
        ptr[i] = page_allocate(size, size);
    }

    for(i = 0;
        i < 16;
        i ++)
    {
        printf("%2i: %p-%p %s\n",
               i,
               ptr[i],
               (void *)((uintptr_t)ptr[i] + size - 1),
               (llabs(ptr[i] - cmp) == size) ? "contiguous" : "");

        cmp = ptr[i];
    }


    return 1;
}

您永遠不要期望mmap自己提供連續的地址,但是您可以嘗試通過請求一個地址來獲取它們,只要地址范圍是空閑的,該地址就可以使新的映射成為連續的,並且省略MAP_FIXED以便所請求的地址僅是用作提示(使用MAP_FIXED ,它將替換已經存在的內容,這絕對不是您想要的)。

我懷疑您看到mmap為某些調用(但不是全部)返回連續映射的原因是內核試圖平衡使新VM區域的成本與希望地址不可預測(ASLR)的成本之間的平衡。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM