代码之家  ›  专栏  ›  技术社区  ›  Samuel Danielson

当“char bigchar[1u<<31-1];”工作正常时,为什么要使用malloc()?

  •  7
  • Samuel Danielson  · 技术社区  · 16 年前

    与静态数组相比,使用malloc(除了失败时返回NULL)有什么优势?下面的程序将耗尽我所有的ram,并且仅当循环未注释时才开始填充交换。它不会崩溃。

    ...

    #include <stdio.h>
    
    unsigned int bigint[ 1u << 29 - 1 ];
    unsigned char bigchar[ 1u << 31 - 1 ];
    
    int main (int argc, char **argv) {
      int i;
    /*   for (i = 0; i < 1u << 29 - 1; i++) bigint[i] = i; */
    /*   for (i = 0; i < 1u << 31 - 1; i++) bigchar[i] = i & 0xFF; */
    
      getchar();
      return 0;
    }
    

    编辑:我对为什么使用malloc来管理堆而不是让虚拟内存系统来处理它感兴趣。显然,我可以将一个数组的大小调整到我认为需要的很多倍,而虚拟内存系统将只在ram中保留所需的内容。如果我从未写入这些大型阵列的末尾(或开头),则程序不会使用物理内存。此外,如果我可以写入每个位置,那么malloc除了在堆中增加一个指针或在同一进程中搜索以前的分配之外,还能做什么?

    编者按: 1 << 31 causes undefined behaviour 1u

    8 回复  |  直到 8 年前
        1
  •  16
  •   Vlad Gudim nuriaion    16 年前

    其实有两个原因:

    1. 由于可移植性,因为有些系统不会为您进行虚拟内存管理。

    2. 您将不可避免地需要将此数组划分为更小的块以使其有用,然后跟踪所有的块,最后当您开始“释放”数组中不再需要的部分块时,您将遇到以下问题: memory fragmentation .

    总而言之,您最终将实现许多内存管理功能(实际上几乎是重新实现malloc),而没有可移植性的好处。

    因此,理由如下:

    • 通过内存管理封装和标准化实现代码可移植性。

    • 通过代码重用提高个人生产力。

        3
  •  11
  •   dfa    16 年前

    使用malloc,您可以扩展和缩小阵列:它变得动态,因此您可以精确地分配所需的资源。

        4
  •  7
  •   alamar    5 年前

    我想这就是所谓的自定义内存管理。 你可以这样做,但你必须自己管理那块内存。

        5
  •  3
  •   Lance Richardson    16 年前

    经过反复试验,我找到了答案 上面是最大的静态数组 在我的32位Intel计算机上允许 限制、编译器限制或机器 限度

    一个上限取决于4GB(32位)虚拟地址空间在用户空间和内核空间之间的划分方式。对于Linux,我认为最常见的分区方案对于用户空间有3 GB的地址范围,对于内核空间有1 GB的地址范围。分区在内核构建时是可配置的,2GB/2GB和1GB/3GB分割也在使用中。加载可执行文件时,必须为每个对象分配虚拟地址空间,而不管是否分配了实际内存对其进行备份。

        6
  •  3
  •   Timothy Place    16 年前

    如前所述,您还可以调整内存大小,以完全使用所需的内容。在性能关键的上下文中,如果可以避免的话,不分页到虚拟内存是很重要的。

        7
  •  3
  •   Pasi Savolainen    16 年前

    除了超出范围之外,没有其他方法可以释放堆栈分配。所以,当您实际使用全局分配时,VM必须分配给您真正的硬内存,它将被分配并一直保留,直到您的程序用完为止。这意味着任何进程只会在其虚拟内存使用中增长(函数具有本地堆栈分配,这些将被“释放”)。

    一旦堆栈内存超出函数范围,就不能“保留”它,它总是被释放的。所以,您必须知道在编译时将使用多少内存。

    这就归结为您可以拥有多少int foo[1<<29]。因为第一个会占用整个内存(32位)并且会(让我们假设:0x000000),所以第二个会解析为0xffffffff或其他。那么第三个会决定什么?32位指针无法表示的内容。(请记住,堆栈保留在编译时部分解析,在运行时部分解析,通过偏移量,当您分配此变量或该变量时,堆栈偏移量被推多远)。

    所以答案是,一旦你有了int-foo[1<<29],你就不能再有任何合理深度的函数和其他局部堆栈变量了。

        8
  •  2
  •   Joey Joey    16 年前

    除非你知道自己在做什么,否则你真的应该避免这样做。尽量只请求所需的内存。即使它没有被使用,或者妨碍了其他程序,它自己也会把这个过程搞砸。这有两个原因。首先,在某些系统上,特别是32位系统上,在极少数情况下,它会导致地址空间过早耗尽。此外,许多内核对保留/虚拟/未使用内存有某种进程限制。如果您的程序在运行时请求内存,如果内核请求保留超过此限制的内存,那么它可以终止进程。我见过由于malloc失败而崩溃或退出的程序,因为它们保留了GBs的内存,而只使用了很少的MB。