簡體   English   中英

內存大小隨着動態2D內存分配而過度增長

[英]Memory size grows exorbitantly with dynamic 2D memory allocation

我有以下一段示例代碼分配1D數組:

#define C 3
int main() {
    int *a;
    long long N = 1000000000, i;
    a = (int*)malloc(sizeof(int) * N * C);
    for (i = 0; i < N * C; i++)
        a[i] = i / 2;
    printf("%d\n", a[N*C - 1]);
    return 0;
}

上面的代碼在內存中只占用12 GB的數據。
請注意, sizeof(int) == 4sizeof(int*) == 8

現在,如果我使用以下代碼實現動態2D數組:

#define C 3
int main() {
    int **a;
    long long N = 1000000000, i;
    a = (int**)malloc(sizeof(int*) * N);
    for (i = 0; i < N; i++)
       a[i] = (int*)malloc(sizeof(int) * C);
    for (i = 0; i < N; i++)
       for (j = 0; j < C; j++)
           a[i][j] = i;
    printf("%d\n", a[N-1][C-1]);
    return 0;
}

上面的代碼奇怪地需要大約38 GB的內存(雖然它應該采用12GB + 8GB(對於指針數組)= 20 GB。

奇怪的是,在第二個示例代碼中,如果我將C的值增加到4,5,6,消耗的內存完全相同(38 GB),而對於C=7C=8 ,消耗的內存為54 GB ,對於C=16 ,消耗的內存為86 GB。 這不符合我能想到的任何數學。 任何人都可以幫我解決這個問題嗎?

你的2D數組實際上是一個指向3 int數組的指針數組。 所需的額外空間來自3 int所有小數組中的開銷:每個數組使用12個字節加上可能的4到12個字節的填充和估計的至少8個字節的開銷。 總大小可達32GB + 8GB = 40GB,據top報道為38GiB。 根據malloc的實際實現,開銷可以從更少到更多。 malloc返回的malloc保證適當地對齊以滿足最大對齊要求。 在intel 64位架構上,這意味着16個字節。 如果分配器非常保守,則每個小數組占用16個字節,否則可能占用32個字節或更多。

您可以通過這種方式分配一個真正的2D數組,而無需開銷:

#define C 3
int main(void) {
    long long N = 1000000000, i;
    int (*a)[C] = malloc(sizeof(*a) * N);
    for (i = 0; i < N; i++) {
        for (j = 0; j < C; j++)
            a[i][j] = i;
    }
    printf("%d\n", a[N-1][C-1]);
    return 0;
}

編輯試圖解釋你的大小觀察:

C=3 to C=6 -> 38GiB
C=7, C=8 -> 54 GiB
C=16 ->  86 GiB

top以GiB顯示內存大小,單位為1024x1024x1024字節,比GB小約8%。

指針數組恰好使用8GB(80億字節),開銷可以忽略不計。

下表總結了指針數組與使用malloc分配的大小為C的各個int數組之間的細分:

 C    used    actual   arrays  pointers  total    binary
---   ----    ------   ------  --------  -----    ------
 3     12       32      32GB      8GB     40GB   37.3GiB
 4     16       32      32GB      8GB     40GB   37.3GiB
 5     20       32      32GB      8GB     40GB   37,3GiB
 6     24       32      32GB      8GB     40GB   37.3GiB
 7     28       48      48GB      8GB     56GB   52.2GiB
 8     32       48      48GB      8GB     56GB   52.2GiB
16     64       80      80GB      8GB     88GB   82.0GiB

我的解釋是:

malloc分配的小內存塊被舍入到16加8的大小倍數,以及競技場簿記信息的額外8字節開銷。 malloc返回的地址在16字節邊界上對齊,8字節開銷位於塊之前,塊大小是16減8字節的倍數,以允許下一個塊對齊。

這可以解釋C = 7從32跳到48字節的跳轉。

你應該驗證C = 11有類似的跳躍。

您還可以測量C = 2的大小寫,以查看塊大小為8或24字節的最小塊大小

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM