【问题标题】:malloc() 5GB memory on a 32 bit machinemalloc() 32 位机器上的 5GB 内存
【发布时间】:2015-07-23 12:08:47
【问题描述】:

我在看书:

32 位机器上进程的虚拟地址空间是 2^32,即 4Gb 的空间。程序中看到的每个地址都是虚拟地址。 4GB 空间进一步通过用户/内核拆分 3-1GB。

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

【问题讨论】:

  • 真的 malloc 了所有内存吗?可以贴一下相关代码吗?
  • 如果使用 32 位指针,则无法寻址 5GB,因此也无法打印所有地址。它将换行为零。
  • 打印地址与该地址是否可用完全无关。并且 Linux 在您使用它之前实际上不会提交分配的内存。
  • AFAIK,即使您有超过 4GB 的 RAM,一个进程也不能在 32 位操作系统/CPU 上处理超过 4GB 的内存,因为 size_t 长度是 malloc 的参数并处理最大指针大小。因此,您必须创建单独的进程并分配尽可能多的内存,并将这些内存作为共享来处理。
  • 这是一个很好的例子,切换所有编译器警告或忽略它们是有意义的。使用 size_t 参数并在那里写入 5GB 常量应该会导致警告(gcc 的“表达式中的整数溢出”)。但非常有趣的是,您能够使用指针在 32 位系统上运行超过 5GB。也忽略了很多警告?提示:阅读并理解编译器警告!

标签: c linux linux-kernel operating-system


【解决方案1】:

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

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

因此,绝对没有办法告诉内核您希望通过一次调用获得超过 4GB 的内存)而且这并非偶然 - 无论如何这都没有任何意义。

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

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

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 $

【讨论】:

  • size_t 在 32 位系统上是 unsigned long(或 long unsigned int),但它也是 32 位数据类型。
  • “所以绝对没有办法告诉内核你想要分配超过 4GB 的内存。” nitpick:当然有,只是不是一大堆;)
  • @mch:嗯,实际上这取决于实现。例如,在 gcc 中,它被定义为 __SIZE_TYPE__,如果我的编译器实际上是“unsigned int”
  • @KrzysztofAdamski:这实际上是一个编程错误。我以为 malloc() 成功了 5gb。我为此不满了一个星期。感谢您的精彩解释!
【解决方案2】:

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

#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
试图分配 4294967295 个字节
malloc(): 无法分配内存

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-29
      • 2018-04-18
      • 2023-03-29
      • 2011-02-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多