【问题标题】:mmap substitute for mallocmmap 替代 malloc
【发布时间】:2013-01-25 00:57:56
【问题描述】:

我需要找到一种方法来使用 mmap 而不是 malloc。这怎么可能? (我不只使用 libc 系统调用)是的 brk() 是可能的。我使用了 sbrk() 但意识到它不是系统调用...(x86 内联汇编)

我一直在环顾四周,看到了这个:How to use mmap to allocate a memory in heap? 但这对我没有帮助,因为我有一个段错误。

基本上,我只想创建 3 块内存来存储字符。

说,

char * x = malloc(1000);
char * y = malloc(2000);
char * z = malloc(3000);

如何使用 mmap 实现这一点以及以后如何使用 munmap 释放它?

【问题讨论】:

  • kernel.org/doc/man-pages/online/pages/man2/sbrk.2.html 是一个系统调用,但已被弃用。
  • glibc malloc 在适当的情况下使用mmap(例如,如果要分配的字节数超过某个阈值)
  • 取自 malloc 手册页:通常,malloc() 从堆中分配内存,并根据需要使用 sbrk(2) 调整堆的大小。当分配大于 MMAP_THRESHOLD 字节的内存块时,glibc malloc() 实现使用 mmap(2) 将内存分配为私有匿名映射。 MAP_THRESHOLD 默认为 128 kB,但可以使用 mallopt(3) 进行调整。使用 mmap(2) 执行的分配不受 RLIMIT_DATA 资源限制的影响(请参阅 getrlimit(2))。
  • 你怎么不用libc? mmap 和 malloc 是 libc 调用。
  • @LtWorf: malloc 确实是一个标准的libc 函数,但mmap 是一个系统调用,可以在没有任何库的情况下调用......就像Flexo 的答案所示...... .

标签: c assembly x86 malloc mmap


【解决方案1】:

您是否仔细阅读了mmap(2) 手册页?建议多读几遍。

请注意,您只能要求内核 [通过 mmap 等...] 管理与页面大小对齐的内存以及页面大小的倍数 sysconf(_SC_PAGE_SIZE),这通常是 4096 字节(我假设在我的回答中) .

那么你可能会这样做:

  size_t page_size =  sysconf(_SC_PAGE_SIZE);
  assert (page_size == 4096); // otherwise this code is wrong

  // 1000 bytes fit into 1*4096
  char *x = mmap (NULL, page_size, PROT_READ|PROT_WRITE, 
                  MAP_ANONYMOUS, -1, (off_t)0);
  if (x == MMAP_FAILED) perror("mmap x"), exit (EXIT_FAILURE);

  // 2000 bytes fit into 1*4096
  char *y = mmap (NULL, page_size, PROT_READ|PROT_WRITE, 
                  MAP_ANONYMOUS, -1, (off_t)0);
  if (y == MMAP_FAILED) perror("mmap y"), exit (EXIT_FAILURE);

稍后释放内存,使用

  if (munmap(x, page_size))
     perror("munmap x"), exit(EXIT_FAILURE);

如果要分配 5Kbytes,则需要两页(因为 5Kbytes 1*4096)即mmap(NULL, 2*page_size, ...

实际上,你所有的xyz 只占用 8000 字节,可以放入两页,而不是三页……但你只能将 munmap 内存放在一起。

请注意,mmap 是一个系统调用,可能非常昂贵。 malloc 实现注意避免过于频繁地调用它,这就是为什么他们以前管理free-d 区域以便以后重用它们(进一步malloc-s)而无需任何系统调用。在实践中,大多数malloc 实现管理不同的大分配(例如超过一兆字节),通常mmap-ed 在mallocmunmap-ed 在free 时间......你可以学习一些malloc的源代码。来自MUSL Libc 的可能比 Glibc malloc 更容易阅读。

顺便说一句,/proc/1234/maps 文件向您显示了 pid 1234 进程的内存映射。也可以在终端中尝试cat /proc/self/maps,它会显示该cat 进程的内存映射。

【讨论】:

  • 谢谢,帮了大忙!
  • 应该是“sysconf(_SC_PAGESIZE)”吗?
【解决方案2】:

您可以调用 mmap 在 x86 asm 中进行匿名映射,例如:

    mov eax, 192    ; mmap
    xor ebx, ebx    ; addr   = NULL
    mov ecx, 4096   ; len    = 4096
    mov edx, $7     ; prot   = PROT_READ|PROT_WRITE|PROT_EXEC
    mov esi, $22    ; flags  = MAP_PRIVATE|MAP_ANONYMOUS
    mov edi, -1     ; fd     = -1 (Ignored for MAP_ANONYMOUS)
    xor ebp, ebp    ; offset = 0 (4096*0) (Ignored for MAP_ANONYMOUS)
    int $80         ; make call (There are other ways to do this too)

【讨论】:

    猜你喜欢
    • 2017-11-05
    • 2015-03-21
    • 2014-07-20
    • 2010-12-16
    • 2015-08-13
    • 1970-01-01
    • 2012-10-30
    • 1970-01-01
    • 2014-02-02
    相关资源
    最近更新 更多