malloc 会四舍五入到最接近的页面大小吗?

问题描述

我不确定我是不是在这里问一个菜鸟问题,但我走了。我也搜索了很多类似的问题,但一无所获。

所以,我知道 mmapbrk 是如何工作的,而且无论您输入的长度如何,它都会将其四舍五入到最近的页面边界。我也知道 malloc 使用 brk/sbrkmmap(至少在 Linux/Unix 系统上),但这提出了一个问题:malloc 是否也四舍五入到最接近的页面大小?对我来说,页面大小是 4096 字节,所以如果我想用 malloc 分配 16 字节,4096 字节是......比我要求的多得多。

解决方法

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <unistd.h>


int main(void) {
    void *a = malloc(1);
    void *b = malloc(1);
    uintptr_t ua = (uintptr_t)a;
    uintptr_t ub = (uintptr_t)b;
    size_t page_size = getpagesize();

    printf("page size: %zu\n",page_size);
    printf("difference: %zd\n",(ssize_t)(ub - ua));
    printf("offsets from start of page: %zu,%zu\n",(size_t)ua % page_size,(size_t)ub % page_size);
}

印刷品

page_size: 4096
difference: 32
offsets from start of page: 672,704

很明显,在这种情况下它没有四舍五入到页面大小,这证明它并不总是四舍五入到页面大小。


如果您将分配更改为某个任意大的大小,它将命中 mmap。例如:

void *a = malloc(10000001);
void *b = malloc(10000003);

我得到:

page size: 4096
difference: -10002432
offsets from start of page: 16,16

而且很明显起始地址仍然没有页面对齐;簿记必须存储在下方指针并且指针需要充分对齐以实现通常所需的最大对齐 - 您可以使用 free 进行推理 - 如果 { {1}} 只是给了一个指针,但它需要弄清楚分配的大小,它可以在哪里寻找它,只有两种选择是可行的:在一个单独的数据结构中,列出所有基指针及其分配大小,或者在当前指针下方的某个偏移处。其中只有一个是理智

,

malloc 和朋友们的基本工作是管理这样一个事实,即操作系统通常只能(有效地)处理大分配(整个页面和页面的范围),而程序通常需要更小的块和更细粒度的管理。

那么 malloc (通常)所做的是,第一次调用它时,它从系统中分配了大量内存(通过 mmap 或 sbrk -- 可能是一页或可能是许多页),并使用一个小的一些数据结构跟踪堆使用的数量(堆在哪里,哪些部分正在使用以及哪些部分是空闲的),然后将该空间的其余部分标记为空闲。然后它会从该空闲空间分配您请求的内存,并将剩余的内存用于后续的 malloc 调用。

因此,当您第一次调用 malloc 获取例如 16 个字节时,它将使用 mmap 或 sbrk 分配一个大块(可能是 4K 或 64K 或 16MB 甚至更多)并将其初始化为大部分空闲并返回一个指针到某个地方的 16 个字节。再次调用 malloc 获取另外 16 个字节只会从该池中返回另外 16 个字节——无需返回操作系统获取更多信息。

当你的程序继续分配更多的内存时,它只会来自这个池,并且空闲调用会将内存返回到空闲池。如果它通常分配的比它释放的多,最终该空闲池将耗尽,此时,malloc 将调用系统(mmap 或 sbrk)以获取更多内存以添加到空闲池中。

这就是为什么如果您使用某种进程监视器监视正在使用 malloc/free 分配和释放内存的进程,您通常只会看到内存使用量上升(因为空闲池用完并且需要更多内存)从系统中),并且通常不会看到它下降——即使内存被释放,它通常只会回到空闲池并且不会被取消映射或返回到系统。有一些例外情况——特别是当涉及非常大的块时——但通常在进程退出之前你不能依赖任何内存返回给系统。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...