簡體   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