2015-04-13 3 views
3

Я сделал минимально-рабочий пример того, как добавлять элементы в массив с realloc. Это будет расширено в будущей программе, в которой будет много других элементов.Realloc Использование слишком большого объема памяти

#include <stdio.h>//printf 
#include <stdlib.h>//malloc, realloc 

int main() { 
//BEGIN REALLOCATE-ABLE ARRAY 
    unsigned int *array, loop_variable; 
    const unsigned int ORIGINAL_ARRAY_SIZE = 4, REALLOC_INDICES = 99; 
    array = malloc(ORIGINAL_ARRAY_SIZE*sizeof(unsigned int)); 
    for (loop_variable = 0; loop_variable < ORIGINAL_ARRAY_SIZE; loop_variable++) { 
     array[loop_variable] = loop_variable; 
    } 
//BEGIN REALLOCATION 
    for (loop_variable = 1; loop_variable < REALLOC_INDICES; loop_variable++) { 
     array = realloc(array,sizeof(unsigned int)*(ORIGINAL_ARRAY_SIZE+loop_variable)); 
     array[ORIGINAL_ARRAY_SIZE+loop_variable-1] = 2*(ORIGINAL_ARRAY_SIZE+loop_variable-1); 
     printf("reallocate array[%d] = %d\n",ORIGINAL_ARRAY_SIZE+loop_variable-1,array[ORIGINAL_ARRAY_SIZE+loop_variable-1]); 
    } 
//BEGIN PRINTING ARRAY VALUES 
    for (loop_variable = 0; loop_variable < ORIGINAL_ARRAY_SIZE+REALLOC_INDICES-1; loop_variable++) { 
     printf("array[%d] = %d\n",loop_variable,array[loop_variable]); 
    } 
//BEGIN FREE ARRAY 
    free(array); array = NULL; 
    return 0; 
} 

Это должно скомпилироваться на любом компьютере с gcc или clang. Затем я запускаю эту программу на Valgrind, чтобы убедиться в отсутствии утечек памяти, и я получаю это:

==10791== HEAP SUMMARY: 
==10791==  in use at exit: 0 bytes in 0 blocks 
==10791== total heap usage: 99 allocs, 99 frees, 20,988 bytes allocated 
==10791== 
==10791== All heap blocks were freed -- no leaks are possible 
==10791== 
==10791== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) 
==10791== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) 

Однако то, что меня беспокоит то, что я использую 20,988 байт для массива из 101 элементов. Использование памяти растет экспоненциально по мере увеличения массива, а не линейного на 4 байта/элемента.

Если я правильно понять выход VALGRIND в, этот массив должен иметь 4 * 101 = 404 элементов размером байт памяти, но кажется использовать примерно в 50 раз больше памяти, как это должно быть. Это небольшая проблема для такой небольшой программы, но более значимые программы на этом компьютере исчерпаются.

Мой вопрос: этот массив действительно использует 20,988 байт, или это Valgrind двойной подсчет памяти?

Есть ли более эффективный для памяти способ сделать это? Я не могу понять другие примеры realloc, хотя я старался следовать им настолько близко, насколько я могу, и сделать этот вопрос актуальным для максимально возможного числа пользователей.

+1

не Valgrind отчетности суммарных размеров в '' malloc' и realloc' аргументов как 'общей кучи usage', игнорируя все' free's? – pts

+2

Вы уверены, что растет экспоненциально, а не O (n^2)?20988 довольно близко к 4 * 101 * 101/2. – pts

+0

всегда проверяют (! = NULL) возвращаемое значение из malloc и семейство функций, чтобы гарантировать успешную работу. – user3629249

ответ

5
==10791==  in use at exit: 0 bytes in 0 blocks 
==10791== total heap usage: 99 allocs, 99 frees, 20,988 bytes allocated 

этот массив действительно используя 20,988 байт

Нет, он использует 0 байт.

«выделено», очевидно, означает «когда-либо выделенное», включая освобожденные байты, поскольку объем памяти «все еще выделен» равен нулю (и другая строка сообщает об этом).

+0

Программа «когда-либо выделяет» всего 100 раз 4 байта. Общее количество запросов на повторный запрос составляет 20 200 байт (то есть: 4+ (4 + 4) + (4+ (4 + 4)) + ...). По-прежнему осталось 788 байт - может быть, это накладные расходы? –

+0

@PaulOgilvie Выполняя программу под Valgrind, вы ** просите ** ее запустить в среде, где 'realloc' всегда создает новый блок и освобождает старый, поскольку это то, как ошибка программирования с использованием старого указатель после вызова 'realloc'. Я не использую Valgrind, потому что я работаю над своей собственной подобной системой, но так работает моя система, я был бы удивлен, если бы система Valgrind тоже не работала. Кроме того, теперь, когда мы установили, что «использование кучи» - это только статистика, вычисленная с необычным алгоритмом, о чем мы спорим? –

+0

@PaulOgilvie: из-за ограничений выравнивания 'malloc()' и 'realloc()' эффективно возвращают память в дискретных размерах, которые на каждой реализации x86, на которую я смотрел, всегда кратно 8 байтам. Рассмотрение исходного кода Valgrind может означать, что он подсчитывает количество выделенной памяти в таких кусках. Это объясняет некоторые из указанных вами несоответствий. –

0

Ответ, благодаря пользователю Pascal Cuoq, заключается в том, что Valgrind будет суммировать распределения памяти для каждого распределения. Вот почему я смутился и думал, что realloc использует слишком много памяти.

Я подумал, что если вы хотите, чтобы найти размер массива, вы можете закомментировать строку, которая говорит

free(array); array = NULL; 

намеренно ввести ошибку памяти, и Valgrind будет выводить

==11699== LEAK SUMMARY: 
==11699== definitely lost: 408 bytes in 1 blocks 
==11699== indirectly lost: 0 bytes in 0 blocks 
==11699==  possibly lost: 0 bytes in 0 blocks 
==11699== still reachable: 0 bytes in 0 blocks 
==11699==   suppressed: 0 bytes in 0 blocks 
==11699== 
==11699== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0) 
==11699== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0) 

, который дает вам истинный размер массива на последней итерации. Вероятно, есть лучший способ сделать это, но моя точка зрения сделана.

Я добавил улучшения, предлагаемые другими пользователями здесь. Мне очень трудно найти хорошие, минимальные рабочие примеры realloc в поисковых системах, и для будущего использования любого, кто найдет это в поисковой системе, это очень простой минимальный рабочий пример хорошего, но, вероятно, не самого лучшего, как использовать перераспределить в C:

#include <stdio.h>//include printf function 
#include <stdlib.h>//include malloc, realloc functions 

int main() { 
/*BEGIN REALLOCATE-ABLE ARRAY*/ 
    unsigned int *array, loop_variable; 
    const unsigned int ORIGINAL_ARRAY_SIZE = 4, REALLOC_INDICES = 99999; 
    array = malloc(ORIGINAL_ARRAY_SIZE*sizeof(unsigned int)); 
    for (loop_variable = 0; loop_variable < ORIGINAL_ARRAY_SIZE; loop_variable++) { 
     array[loop_variable] = loop_variable; 
    } 
/*BEGIN REALLOCATION*/ 
    for (loop_variable = 1; loop_variable < REALLOC_INDICES; loop_variable++) { 
     array = realloc(array,sizeof(unsigned int)*(ORIGINAL_ARRAY_SIZE+loop_variable)); 
     if (array == NULL) { 
      printf("Array variable %d failed to reallocate :,-(\n",loop_variable); 
      exit(EXIT_FAILURE); 
     } 
     array[ORIGINAL_ARRAY_SIZE+loop_variable-1] = 2*(ORIGINAL_ARRAY_SIZE+loop_variable-1); 
     printf("reallocate array[%d] = %d\n",ORIGINAL_ARRAY_SIZE+loop_variable-1,array[ORIGINAL_ARRAY_SIZE+loop_variable-1]); 
    } 
/*BEGIN PRINTING ARRAY VALUES*/ 
    for (loop_variable = 0; loop_variable < ORIGINAL_ARRAY_SIZE+REALLOC_INDICES-1; loop_variable++) { 
     printf("array[%d] = %d\n",loop_variable,array[loop_variable]); 
    } 
/*BEGIN FREE ARRAY*/ 
    free(array); array = NULL; 
    return 0; 
} 
Смежные вопросы