malloc如何请求堆内存

时间:2013-06-07 01:34:11

标签: c arrays malloc

我有一个庞大的数组,我已分配给堆,因为如果留在堆栈上会导致错误。现在我知道有两种方法可以将它发送到堆中。

#1

int i;
int x=10000, int y=10000;
double** array=(double**)malloc(sizeof(double*)*x);
if (image) {
    for (i=0; i<x; i++) {
        array[i] =(double*)malloc(sizeof(double)*y);
    }
}

#2

double *array[x][y]=(double*)malloc(sizeof(double)*x*y);

现在我想知道哪种方法是superoir?我认为#1要求堆中的x个块legnth y,它们不需要彼此相邻。其中#2要求堆中的y * x块。 #2要求一个巨大的x * y块,其中#1要求不需要连接的块。所以#1会成为superoir,因为它可能会分裂。假设堆无法处理长度为x * y的巨大条带可以处理x个y条带数据。

首先,这是真的吗?我错过了任何一种方法吗?我的论点是否实际,或者如果是真的,是不是可能的情况?有更多的superoir方法?

感谢您的见解。

2 个答案:

答案 0 :(得分:4)

你是正确的,第一种方法可能更灵活,因为它不需要找到总大小的连续空闲内存范围,而第二种方法可以。这可能产生的不利影响是,如果分配的板块不连续,这本身可能会导致堆碎片更多碎片。在每个板块之间将存在空间区域,未来的分配将需要在其中找到空间。

然而,第二个选项可能会利用spatial and temporal locality。基本上,由于更多的数据彼此相邻,所以您需要的数据在CPU缓存中的可能性会增加,因此,在此内存上运行的速度会快得多。

答案 1 :(得分:1)

它取决于您使用的内存分配器以及x和y的值。

内存分配器通常会在用户空间中缓存小内存块并处理用户空间中的小分配,同时通过mmap将更大的分配请求转发给内核。

大多数内存分配器的工作方式如下:

void* malloc(size_t size)
    if (size > THRESHOLD) {
        return large_alloc(size)     // forward to mmap
    }
retry:
    void* ret = small_alloc(size);   // handled in user space
    if (ret == NULL) {               // no small blocks left
        enlarge_heap();              // map more memory from kernel
        goto retry;
    }
    return ret;
}

在你的情况下,y == 10000,所以你要求一个80000字节的内存块。在glibc中的默认内存分配器中,mmap阈值为128kB。因此,如果分配器已经缓存了足够的内存,则此请求往往会在用户空间中处理。但#2会调用mmap调用,因为它大于128kB。

但是,在你的例子中x == 10000.所以你在谈论一个mmap系统调用和用户空间中的10000个分配。相信我。 #2更快:

在高度优化的分配器实现中的分配在现代x86机器上总是需要超过70个周期。 10000次分配将消耗超过700000个周期。但典型的mmap调用延迟应不超过100000个周期。所以#2更好。

对于其他分配器,例如TCMalloc,它有点不同。 TCMalloc没有这样的阈值,并且总是尝试在其Span结构中处理用户空间中的大量分配请求。所以#2肯定要好得多,因为它只需要一次分配。


我同意#1更灵活,因为#2要求分配器找到一个大的连续内存块。但请记住,它只在虚拟内存中是连续的,并且当您第一次触摸它时,物理页面会按需映射。这意味着它不需要在物理内存中连续。并且通常很容易在虚拟内存中找到8 * 10000 * 10000字节的连续内存区域。