malloc() 32 位机器上的 5GB 内存

malloc() 5GB memory on a 32 bit machine

我正在看书:

The virtual address space of a process on a 32 bit machine is 2^32 i.e. 4Gb of space. And every address seen in the program is a virtual address. The 4GB of space is further goes through user/kernel split 3-1GB.

为了更好地理解这一点,我执行了 5Gb space 的 malloc() 并尝试打印所有地址。如果我打印地址,当应用程序只有 3GB 的虚拟地址 space 时,它如何打印整个 5Gb 地址?我在这里错过了什么吗?

你不能这样做,因为你没有分配5GB内存的功能。

malloc()size_t 作为参数。在 32 位系统上,它是某些无符号 32 位整数类型的别名。这意味着您不能传递任何大于 2^32-1 的值作为 malloc() 的参数,因此无法使用此函数请求分配超过 4GB 的内存。

所有其他可用于分配内存的函数也是如此。最终它们都以 brk()mmap 系统调用结束。 mmap() 的长度参数也是 ssize_t 类型,在 brk() 的情况下,您必须为分配的 space 的新末端提供一个指针。指针又是 32 位的。

所以绝对没有办法告诉内核你想通过一次调用分配超过 4GB 的内存)而且这不是偶然的 - 这无论如何都没有任何意义。

现在确实可以多次调用 malloc 或其他分配内存的函数,总共请求超过 4GB。如果您尝试这样做,后续调用(这会导致将分配的内存扩展到超过 3GB)将失败,因为没有地址 space 可用。

所以我猜你要么没有检查 malloc return 值,要么你确实尝试 运行 像这样(或类似的东西)的代码:

int main() {
    assert(malloc(5*1<<30));
}

并假设您成功分配了 5GB,但没有验证您的参数是否溢出,您请求的不是 5368709120 字节,而是 1073741824。在 Linux 上验证这一点的一个示例是使用:

$ ltrace ./a.out __libc_start_main(0x804844c, 1, 0xbfbcea74, 0x80484a0, 0x8048490 <unfinished ...> malloc(1073741824) = 0x77746008 $

已经有很好的答案了。为了以防万一,您的虚拟地址 space 的大小可以像这样轻松验证:

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

int main()
{
    size_t size = (size_t)-1L;
    void *foo;

    printf("trying to allocate %zu bytes\n", size);

    if (!(foo = malloc(size)))
    {
        perror("malloc()");
    }
    else
    {
        free(foo);
    }
}

> gcc -m32 -omalloc malloc.c && ./malloc
trying to allocate 4294967295 bytes
malloc(): Cannot allocate memory

这肯定会失败,因为您的部分地址 space 已经被占用:当然,被内核的映射部分、映射的共享库和您的程序占用。