一个malloc在C中有多大?

时间:2010-08-11 22:01:22

标签: c macros malloc totalview

我在C中有一个malloc,它是26901 ^ 2 * sizeof(double)

这让我想到这里最大的价值是什么?

另外,定义宏来访问这个2D数组会有什么问题吗?

 #define DN(i,j) ((int)i * ny + (int)j)

因为这对我来说似乎不起作用 - 或者我至少不确定它是否适用。我无法弄清楚如何在一个宏上进行全视图潜水,告诉我A [DN(indx,jndx)]实际上在看什么。

6 个答案:

答案 0 :(得分:38)

观察

假设一个典型的分配器,例如一个glibc使用的,有一些观察结果:

  1. 无论是否实际使用内存,都必须在虚拟内存中连续保留该区域。
  2. 最大的免费连续区域取决于现有内存区域的内存使用情况,以及malloc区域的可用性。
  3. 映射实践取决于体系结构和操作系统。此外,获取内存区域的底层系统调用受这些实践的影响(例如malloc调用mmap来获取页面)。
  4. 实验

    这是一个simple program来分配最大可能的块(使用gcc largest_malloc_size.c -Wall -O2编译:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    static void *malloc_wrap(size_t size)
    {
        void *p = malloc(size);
        if (p) {
            printf("Allocated %zu bytes from %p to %p\n", size, p, p + size);
        }
        else {
            printf("Failed to allocated %zu bytes\n", size);
        }
        return p;
    }
    
    int main()
    {
        size_t step = 0x1000000;
        size_t size = step;
        size_t best = 0;
        while (step > 0)
        {
            void *p = malloc_wrap(size);
            if (p) {
                free(p);
                best = size;
            }
            else {
                step /= 0x10;
            }
            size += step;
        }
        void *p = malloc_wrap(best);
        if (p) {
            pause();
            return 0;
        }
        else {
            return 1;
        }
    }
    

    在我的./a.out计算机上运行上述程序(Linux stanley 2.6.32-24-generic-pae #39-Ubuntu SMP Wed Jul 28 07:39:26 UTC 2010 i686 GNU/Linux)可获得此结果:

    <snip>
    Allocated 2919235584 bytes from 0x9763008 to 0xb7763008
    Allocated 2936012800 bytes from 0x8763008 to 0xb7763008
    Failed to allocated 2952790016 bytes
    Failed to allocated 2953838592 bytes
    Failed to allocated 2953904128 bytes
    Failed to allocated 2953908224 bytes
    Allocated 2936012800 bytes from 0x85ff008 to 0xb75ff008
    

    这是2800MiB的分配。观察/proc/[number]/maps的相关映射:

    <snip>
    0804a000-0804b000 rw-p 00001000 08:07 3413394    /home/matt/anacrolix/public/stackoverflow/a.out
    085ff000-b7600000 rw-p 00000000 00:00 0          [heap]
    b7600000-b7621000 rw-p 00000000 00:00 0 
    b7621000-b7700000 ---p 00000000 00:00 0 
    b7764000-b7765000 rw-p 00000000 00:00 0 
    b7765000-b78b8000 r-xp 00000000 08:08 916041     /lib/tls/i686/cmov/libc-2.11.1.so
    <snip>
    bfc07000-bfc1c000 rw-p 00000000 00:00 0          [stack]
    

    结论

    看起来堆已在程序数据和代码之间的区域以及共享库映射中扩展,这些映射紧贴user/kernel memory space boundary(显然是此系统上的3G / 1G)。

    此结果表明使用malloc的最大可分配空间大致等于:

    1. 用户空间区域(示例中为3GB)
    2. 减去堆开始的偏移量(程序代码和数据)
    3. 减少为主线程堆栈保留的空间
    4. 减少共享库中所有映射所占用的空间
    5. 最后,堆可用区域内的底层系统调用可以找到最大的连续区域(可能被其他映射分段)
    6. 备注

      关于glibc和Linux实现,以下手册片段引起了极大的兴趣:

      malloc

         Normally, malloc() allocates memory from the heap, and adjusts the size
         of the heap as required, using sbrk(2).  When allocating blocks of mem‐
         ory larger than MMAP_THRESHOLD bytes, the glibc malloc() implementation
         allocates the memory as a  private  anonymous  mapping  using  mmap(2).
         MMAP_THRESHOLD  is  128  kB  by  default,  but is adjustable using mal‐
         lopt(3).
      

      mmap

         MAP_ANONYMOUS
                The mapping is not backed by any file; its contents are initial‐
                ized to zero.
      

      后记

      此测试在x86内核上完成。我期望x86_64内核有类似的结果,尽管返回的内存区域要大得多。其他操作系统的映射位置和大malloc的处理可能会有所不同,因此结果可能会有很大不同。

答案 1 :(得分:11)

这取决于你的malloc实现!

根据维基百科的说法,“自从v2.3发布以来,GNU C库(glibc)使用了一个修改过的ptmalloc2,它本身就是基于dlmalloc v2.7.0。” dlmalloc指的是Doug Lea的malloc实现。在这个实现中需要注意的重要事项是大型malloc是通过操作系统的内存映射文件功能来完成的,所以这些块确实非常大,没有很多找到连续块的问题。

答案 2 :(得分:7)

回答了malloc问题(取决于操作系统,你没有指定),所以关于那个定义:

#define DN(i,j) ((int)i * ny + (int)j)

不太安全,因为某人可能DN(a+b,c)扩展到

((int)a+b * ny + (int)c)

这可能不是你想要的。所以在那里放了很多括号:

#define DN(i,j) ((int)(i) * ny + (int)(j))

查看DN(indx,jndx)指向的内容,仅printf("%d\n",DN(indx,jndx));

答案 3 :(得分:1)

对malloc的调用中的size参数的类型为size_t,因实现而异。有关详情,请参阅this question

答案 4 :(得分:1)

  

这让我想到这里最大的价值是什么?

26'901 ^ 2 = 723'663'801。如果你的双倍是8字节,那么它小于8GB。我认为分配大量内存完全没问题,我的应用程序经常分配(在64位系统上)更多。 (我见过的最大内存消耗是420GB(在带有640GB RAM的Solaris 10 numa系统上),最大连续块大约为24GB。)

最大的值很难识别,因为它依赖于平台:类似于32位系统,它取决于用户空间/内核空间分割。目前的情况是,我认为在达到libc可以分配的限制之前,首先会达到实际物理RAM的极限。 (并且内核并不关心,它只是在不考虑是否有足够的RAM来固定它的情况下经常扩展虚拟内存。)

答案 5 :(得分:1)

您可以询问 malloc()的最大内存块是最大size_t值 - 来自SIZE_MAX的{​​{1}}。 成功请求的最大金额显然取决于操作系统和单个计算机的配置。

您的宏不安全。它使用<limits.h>变量执行索引计算,该变量仅需要具有最大32767的范围。任何高于此值的值都可能导致签名溢出,从而导致未定义的行为。您可能最好以int进行计算,因为该类型必须能够保存任何有效的数组索引:

size_t

(虽然请注意,如果您为#define DN(i, j) ((size_t)(i) * ny + (size_t)(j)) i提供负值,您将获得远远超出范围的索引。