繁体   English   中英

malloc如何请求堆内存

[英]How malloc ask for heap memory

我有一个巨大的数组分配给堆,因为如果放在堆栈上会导致错误。 据我所知,现在有两种方法可以将其发送到堆中。

#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);

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

首先,这是真的吗? 我是否缺少任何一种方法? 我的论点是否可行,或者如果是,那是不可能的情况吗? 有一种更高级的方法?

感谢您的见识。

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

然而,第二种选择可以利用空间和时间上的局部性 基本上,由于更多数据彼此相邻,因此您需要的数据将更多地存在于CPU缓存中,因此,在此内存上进行操作的速度将大大提高。

它取决于您使用的内存分配器以及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字节的连续内存区域。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM