C(堆)中的多维数组内存使用
Multidimensional Arrays Memory Usage in C (Heap)
我无法理解以下代码的内存使用情况:
typedef struct list{
uint64_t*** entrys;
int dimension;
uint64_t len;
} list;
void init_list(list * t, uint64_t dim, uint64_t length, int amount_reg)
{
t->dimension = dim;
t->len=length;
t->entrys = (uint64_t ***) malloc(sizeof(uint64_t**)*length);
uint64_t i;
for(i=0;i<length;i++)
{
t->entrys[i] = (uint64_t **) malloc(sizeof(uint64_t *)*dim);
int j;
for(j=0;j<dim;j++)
{
t->entrys[i][j]=(uint64_t *) malloc(sizeof(uint64_t)*amount_reg);
}
}
}
int main()
{
list * table = (list *) malloc(sizeof(list));
init_list(table,3,2048*2048,2);
_getch();
}
我想做的是分配 uint64_t 个元素的 3d 数组,例如 table[4194304][3][2].
taskmanager 显示内存使用量为 560MB。 cO
如果我尝试自己计算内存使用量,我无法理解该值。
这是我的计算(对于 x64 系统):
2^20 * 8 Byte (first dimension pointers)
+ 2^20 * 3 * 8 Byte (second dimension pointers)
+ 2^20 * 3 * 2 * 8 Byte (for the values itsself)
= 2^20 * 8 Byte * 10 = 80MB
也许我的计算完全错误,或者我的代码产生了大量开销?!
如果是这样,有没有办法让这个程序更有效地利用内存?
我无法想象像 ~2^23 uint64_t
这样的值需要这么多内存(因为 2^23*8Byte
只是 64MB
)
4194304 不是 2^20,它更像是 2^22,所以你的计算至少有 4 倍的偏差。而且你还分配了一组指针指向其他数据,这需要 space。在您的代码中,第一个 malloc 分配
2048*2048 指针,不是指向那么多项目的单个指针。
您还应该使用动态分配的最佳实践:
1) 不要强制转换 malloc return
2) 始终使用 expression = malloc(count * sizeof *expression);
这样无论您在表达式中使用多少指针级别,您都不会弄错大小。例如
t->entrys = malloc(length * sizeof *t->entrys);
t->entrys[i] = malloc(dim * sizeof *t->entrys[i]);
t->entrys[i][j] = malloc(amount_reg * sizeof *t->entrys[i][j]);
您的代码对 malloc()
进行了 2²² · 4 + 1 = 16777217 次调用。对于每个分配的内存区域,malloc()
都会做一些簿记。当您多次调用 malloc()
时,这会加起来。您可以像这样减少调用 malloc()
次来减少开销:
void init_list(list * t, int dim, uint64_t length, int amount_reg)
{
uint64_t ***entries = malloc(sizeof *entries * length);
uint64_t **seconds = malloc(sizeof *seconds * length * dim);
uint64_t *thirds = malloc(sizeof *thirds * length * dim * amount_reg);
uint64_t i, j;
t->entrys = entries;
for (i = 0; i < length; i++) {
t->entrys[i] = seconds + dim * i;
for (j = 0; j < dim; j++)
t->entrys[i][j] = thirds + amount_reg * j + amount_reg * dim * i;
}
}
这里我们只调用 malloc()
三次,内存使用量从 561272 KiB 下降到 332020 KiB。为什么内存使用率仍然很高?因为你计算有误。分配分配了这么多内存:
- 条目:
sizeof(uint64_t**) * length
= 8 · 2²²
- 秒:
sizeof(uint64_t*) * length * dim
= 8 · 2²² · 3
- 三分之一:
sizeof(uint64_t) * length * dim * amount_reg
= 8 · 2²² · 3 · 2
我们总共有 (1 + 3 + 6) · 8 · 2²² = 335544320 字节(327680 KiB 或 320 MiB)的 RAM,这与观察到的内存量非常匹配。
如何进一步减少这个数额?考虑转置您的数组,以便轴按大小的升序排序。这样你在指针上浪费的内存就会少得多。您还可以考虑仅为值分配 space 并手动进行索引计算。这可以大大加快代码速度(减少内存访问)并节省内存,但编程起来很乏味。
我无法理解以下代码的内存使用情况:
typedef struct list{
uint64_t*** entrys;
int dimension;
uint64_t len;
} list;
void init_list(list * t, uint64_t dim, uint64_t length, int amount_reg)
{
t->dimension = dim;
t->len=length;
t->entrys = (uint64_t ***) malloc(sizeof(uint64_t**)*length);
uint64_t i;
for(i=0;i<length;i++)
{
t->entrys[i] = (uint64_t **) malloc(sizeof(uint64_t *)*dim);
int j;
for(j=0;j<dim;j++)
{
t->entrys[i][j]=(uint64_t *) malloc(sizeof(uint64_t)*amount_reg);
}
}
}
int main()
{
list * table = (list *) malloc(sizeof(list));
init_list(table,3,2048*2048,2);
_getch();
}
我想做的是分配 uint64_t 个元素的 3d 数组,例如 table[4194304][3][2].
taskmanager 显示内存使用量为 560MB。 cO
如果我尝试自己计算内存使用量,我无法理解该值。
这是我的计算(对于 x64 系统):
2^20 * 8 Byte (first dimension pointers)
+ 2^20 * 3 * 8 Byte (second dimension pointers)
+ 2^20 * 3 * 2 * 8 Byte (for the values itsself)
= 2^20 * 8 Byte * 10 = 80MB
也许我的计算完全错误,或者我的代码产生了大量开销?!
如果是这样,有没有办法让这个程序更有效地利用内存?
我无法想象像 ~2^23 uint64_t
这样的值需要这么多内存(因为 2^23*8Byte
只是 64MB
)
4194304 不是 2^20,它更像是 2^22,所以你的计算至少有 4 倍的偏差。而且你还分配了一组指针指向其他数据,这需要 space。在您的代码中,第一个 malloc 分配 2048*2048 指针,不是指向那么多项目的单个指针。
您还应该使用动态分配的最佳实践:
1) 不要强制转换 malloc return
2) 始终使用 expression = malloc(count * sizeof *expression);
这样无论您在表达式中使用多少指针级别,您都不会弄错大小。例如
t->entrys = malloc(length * sizeof *t->entrys);
t->entrys[i] = malloc(dim * sizeof *t->entrys[i]);
t->entrys[i][j] = malloc(amount_reg * sizeof *t->entrys[i][j]);
您的代码对 malloc()
进行了 2²² · 4 + 1 = 16777217 次调用。对于每个分配的内存区域,malloc()
都会做一些簿记。当您多次调用 malloc()
时,这会加起来。您可以像这样减少调用 malloc()
次来减少开销:
void init_list(list * t, int dim, uint64_t length, int amount_reg)
{
uint64_t ***entries = malloc(sizeof *entries * length);
uint64_t **seconds = malloc(sizeof *seconds * length * dim);
uint64_t *thirds = malloc(sizeof *thirds * length * dim * amount_reg);
uint64_t i, j;
t->entrys = entries;
for (i = 0; i < length; i++) {
t->entrys[i] = seconds + dim * i;
for (j = 0; j < dim; j++)
t->entrys[i][j] = thirds + amount_reg * j + amount_reg * dim * i;
}
}
这里我们只调用 malloc()
三次,内存使用量从 561272 KiB 下降到 332020 KiB。为什么内存使用率仍然很高?因为你计算有误。分配分配了这么多内存:
- 条目:
sizeof(uint64_t**) * length
= 8 · 2²² - 秒:
sizeof(uint64_t*) * length * dim
= 8 · 2²² · 3 - 三分之一:
sizeof(uint64_t) * length * dim * amount_reg
= 8 · 2²² · 3 · 2
我们总共有 (1 + 3 + 6) · 8 · 2²² = 335544320 字节(327680 KiB 或 320 MiB)的 RAM,这与观察到的内存量非常匹配。
如何进一步减少这个数额?考虑转置您的数组,以便轴按大小的升序排序。这样你在指针上浪费的内存就会少得多。您还可以考虑仅为值分配 space 并手动进行索引计算。这可以大大加快代码速度(减少内存访问)并节省内存,但编程起来很乏味。