Что не так с моим кодом C для динамического выделения памяти / бесплатно для многомерного массива - PullRequest
0 голосов
/ 05 июля 2011

Я работаю над отладкой программы на Си.Необходим огромный массив данных с 3-мя измерениями.Я разработал две функции для выделения памяти / свободной.

mm() предназначен для размещения со ссылкой на массив, в котором записан размер каждого измерения (вы можете увидеть его в main()).ff() используется для освобождения памяти.

Я проверил свой код командой top после выполнения fr().Это показывает, что память не освобождена.Кто-нибудь может пролить свет на это?

Заранее спасибо!

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
28338 fsdiag    25   0  165m 164m 1208 R 63.2 26.0   0:00.33 a.out
 3439 root      15   0 31740 1180  21m S  1.9  0.2  10:56.47 X


int main(){

unsigned char ***arr;
int dim_len[4]={8832,256,64,0};  // for 3-D array, 0 is mark of tail
unsigned char *p; 

mm( &p, dim_len, 0); arr = (unsigned char ***)p;
ff( (unsigned char **)&arr, dim_len);

while(1){}
return 0;
}

void mm(    unsigned char **a,
            int dim_len[],    //dimension size array guarded by 0 in the tail
            unsigned char data){  //preset data
    if( *dim_len ){
        int i;
        switch(*(dim_len+1)){
            case 0://when allocate memory for unsigned char
                *a = malloc( sizeof(unsigned char) * (*dim_len));
                break;
            default://when allocate memory for pointers
                *a = malloc( sizeof(unsigned char *) * (*dim_len));
                for( i=0; i<(*dim_len); i++){
                    mm( (unsigned char **)&((*a)[i*4]), dim_len+1, data);
                }
                break;
        }//end of switch
    }//end of if
    return;
}


void ff(    unsigned char **a,
            int dim_len[]){//dimension size array guarded by 0 in the tail
    if( *dim_len ){
        int i;
        switch(*(dim_len+1)){
            case 0://when free memory for unsigned char
                free( *a);
                break;
            default://when free memory for pointers
                for( i=0; i<(*dim_len); i++){
                    ff( (unsigned char **)&((*a)[i*4]), dim_len+1); //pointer needs 4 bytes storage
                }
            free( *a );
                break;
        }//end of switch
    }//end of if
    *a = NULL;
    return;
}

Ответы [ 2 ]

3 голосов
/ 05 июля 2011

Вы должны распределить только один кусок памяти с размером произведения чисел в dim_len.

Ваши выделенные данные фрагментированы и больше, чем должны быть, и я изо всех сил пытаюсь представить любой сценарий, в котором ваш код имеет какие-либо преимущества.

0 голосов
/ 05 июля 2011

Определение многомерного массива как массива массивов массивов очень удобно, потому что вы можете обращаться к элементам с привычной нотацией p[i][j][k] вместо выполнения арифметики индекса.Однако другие уже отмечали, что это менее эффективно, чем выделение всего массива в виде большого чанка.

Вы можете получить лучшее из обоих миров с помощью следующего трюка: выделить массив из dim_len[0] указателей намассив dim_len[0]*dim_len[1] указателей на массив dim_len[0]*dim_len[1]*dim_len[2] ячеек данных.Таким образом, у вас есть только три выделения (столько же, сколько измерений), и вы все равно можете использовать простую нотацию p[i][j][k], при условии, что промежуточные массивы указателей правильно инициализированы.И вы также можете выполнять индексную арифметику на **p по вашему выбору.

Вот моя версия вашей программы, использующая этот трюк:

/*
 * Allocation of multidimensional arrays.
 */

 #include <stdio.h>
 #include <stdlib.h>
 #include <assert.h>
 #include <unistd.h>

/*
 * Allocate a multidimensional array of unsigned chars.
 * Cast the returned pointer to (unsigned char **...*)
 */
void *mm(const int dim_len[])
{
    int i, j, size, nmemb = 1, prev_nmemb;
    void *p = NULL, *q = NULL;
    void **prev_q;

    for (i = 0; dim_len[i]; i++) {
        prev_nmemb = nmemb;
        nmemb *= dim_len[i];
        size = dim_len[i+1] ? sizeof(void *) : sizeof(unsigned char);
        prev_q = q;
        q = malloc(nmemb * size);
        if (i == 0) p = q;
        else for (j = 0; j < prev_nmemb; j++)
            prev_q[j] = q + j * dim_len[i] * size;
    }
    return p;
}


/* Free the multidimensional array */
void ff(void *p, int dimensions)
{
    int i;
    void **q;

    for (i = 0; i < dimensions; i++) {
        q = *((void **) p);
        free(p);
        p = q;
    }
}

int main(void)
{
    const int dims[4] = {8832, 256, 64, 0};
    unsigned char ***p;
    int i, j, k;

    printf("Allocating memory.\n");
    p = mm(dims);
    printf("Filling the array.\n");
    for (i = 0; i < dims[0]; i++)
        for (j = 0; j < dims[1]; j++)
            for (k = 0; k < dims[2]; k++)
                p[i][j][k] = (i + 3*j + 5*k) % 256;
    printf("Checking contents.\n");
    for (i = 0; i < dims[0]; i++)
        for (j = 0; j < dims[1]; j++)
            for (k = 0; k < dims[2]; k++)
                assert(p[i][j][k] == (i + 3*j + 5*k) % 256);
    printf("Waiting 10 seconds.\n");
    sleep(10);
    printf("Freeing memory.\n");
    ff(p, 3);
    printf("Waiting 10 seconds.\n");
    sleep(10);
    return 0;
}

Мои тесты показывают, что когда я освобождаюмногомерный массив, память фактически возвращается в ОС.Вот вывод ps непосредственно перед и сразу после освобождения:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
edgar     5201 73.0  3.7 151852 150556 pts/0   S+   14:11   0:00 ./test
edgar     5201  6.1  0.0   1668   408 pts/0    S+   14:11   0:00 ./test
...