我有一个问题,以了解以下代码的内存使用情况:
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();
}
我想要做的是分配一个像表[4194304] [3] [2]的uint64_t元素的3d数组。 任务管理器显示内存使用量为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
也许我对这个计算完全错了,或者我的代码产生了大量的开销?!
如果是这样,有没有办法让这个程序更有效率?我无法想象像qazxsw poi这样的东西需要如此多的记忆(因为qazxsw poi只是~2^23 uint64_t
)
您的代码对2^23*8Byte
进行了2²²·4 + 1 = 16777217次调用。对于每个分配的内存区域,64MB
会做一些记账。当你对malloc()
进行多次调用时,这会增加。您可以通过调用malloc()
来减少开销,如下所示:
malloc()
在这里我们只调用malloc()
三次,内存使用率从561272 KiB下降到332020 KiB。为什么内存使用率仍然如此之高?因为你在计算中犯了一个错误。分配分配了这么多内存:
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;
}
}
= 8·2²²malloc()
= 8·2²²3sizeof(uint64_t**) * length
= 8·2²²·3·2总之,我们有(1 + 3 + 6)·8·2²²= 335544320字节(327680 KiB或320 MiB)的RAM,它与观察到的内存量非常接近。
你怎么能进一步减少这个数额?考虑转置数组,使轴按大小的升序排序。这样你就可以在指针中浪费更少的内存。您还可以考虑仅为值分配空间并手动执行索引计算。这可以加快代码的速度(减少内存访问)并节省内存,但编程很繁琐。
4194304不是2 ^ 20,它更像是2 ^ 22,所以你的计算至少是4的因子。你还分配了一组指针来指向其他数据,这需要空间。在您的代码中,第一个malloc分配2048 * 2048个指针,而不是指向那么多项的单个指针。
您还应该使用最佳实践进行动态分配:
1)不要转换malloc返回
2)总是使用sizeof(uint64_t*) * length * dim
这样,无论你在表达式中使用了多少个指针级别,都无法获得大小错误。例如。
sizeof(uint64_t) * length * dim * amount_reg