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 已经被占用:当然,被内核的映射部分、映射的共享库和您的程序占用。
我正在看书:
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 已经被占用:当然,被内核的映射部分、映射的共享库和您的程序占用。