Я только что начал с C, и имейте очень мало знания о проблемах производительности с malloc()
и free()
. Мой вопрос - это: если я должен был звонить malloc()
сопровождаемый free()
внутри a while
цикл, что циклы для, скажем, 20 повторений, был бы он работать медленнее по сравнению с вызовом free()
вне цикла?
Я на самом деле использую первый метод, чтобы выделить память буферу, считать строку переменной длины из файла, выполнить некоторые строковые операции и затем очистить буфер после каждого повторения. Если бы мой метод приводит к большому количеству издержек затем, я хотел бы попросить лучший способ для меня достигнуть тех же результатов.
Определенно медленнее. (Но помните, что вам нужно сбалансировать количество malloc
и free
, иначе вы получите утечку памяти.)
Если длина меняется, вы можете использовать realloc
], чтобы увеличить размер буфера.
void* v = malloc(1024);
size_t bufsize = 1024;
while(cond) {
size_t reqbufsize = get_length();
if (reqbufsize > bufsize) {
bufsize = reqbufsize * 2;
v = realloc(v, bufsize);
}
// you may shrink it also.
do_something_with_buffer(v);
}
free(v);
Это зависит от реализации malloc и бесплатно.
Лучший способ ответить на ваш вопрос - это построить эталон...
It зависит от того, для чего вам нужен буфер.
Вам действительно нужно очищать его после каждой итерации, или, может быть, символа \ 0
в конце будет достаточно, чтобы отметить конец строки? В конце концов, это то, что используют различные вызовы библиотеки str
.
Если вам действительно нужно очистить его, вы можете использовать bzero ()
. Конечно, выделение и освобождение на каждой итерации - это пустая трата ресурсов, поскольку вы можете с удовольствием повторно использовать буфер.
Другая проблема могла бы возникнуть, если бы вы распараллелили цикл for, т.е. если бы его использовали несколько параллельных потоков.
Простой пример из реальной жизни: использование ведра для переноски воды. Предположим, вам нужно совершить несколько поездок с этим ведром: имеет ли смысл поднять его, использовать, положить, снова поднять, использовать и т. Д.? Вы можете повторно использовать ведро столько раз, сколько сможете. Если, с другой стороны, ведро необходимо использовать вам и большему количеству людей, либо вы организуете доступ к нему, либо вам нужно больше корзин.
Последнее предложение: не беспокойтесь о выступлениях . Говорят, что ранняя оптимизация - это корень всех зол, и вы скоро поймете, почему.
Во-первых, разберитесь в проблеме: напишите код, который можно выбросить. Экспериментируйте.
Во-вторых, проверьте это.Убедитесь, что он делает то, что вам нужно.
В-третьих, оптимизируйте его. Запустите цикл десять тысяч раз и измерьте, сколько времени это займет. Затем переместите malloc наружу и снова измерьте (используйте команду оболочки time
в UNIX).
В-четвертых, перепишите его, потому что ваш первый эксперимент, скорее всего, будет состоять из множества исправлений кода, который не работает.
Промыть, повторить.
ps: развлекайтесь пока что. Это должно быть интересно, а не расстраивать.
Для 20 итераций вам не стоит беспокоиться о производительности malloc/free.
Даже при значительно большей производительности (на пару порядков) не стоит начинать думать об оптимизации, пока вы не профилируете код и не поймете, что именно работает медленно.
Наконец, если вы собираетесь освободить буфер, нет необходимости сначала очищать его. Даже если вы перенесете malloc/free за пределы цикла (используя максимальный буфер, как предложил Джастин), вам не нужно явно очищать буфер.
Если вы знаете максимальную длину буфера или можете установить разумный максимум, то вы можете использовать один и тот же буфер для каждой итерации. В противном случае то, что вы делаете, должно быть в порядке.
Вообще все, что можно переместить за пределы цикла, должно быть перемещено. Зачем повторять одно и то же действие, если можно сделать это один раз?
Джастин Этье прав: выделите буфер, в который удобно поместится самая большая строка, и используйте его повторно.
Вы не можете вызвать free за пределами цикла, если вы вызываете malloc внутри:
char * buffer;
for (int i = 0; i < num_files; i++) {
buffer = malloc(proper_length(i));
// do some things with buffer
}
free(buffer);
Вы будете malloc'ed num_files
раз, но только один раз - вы утекли память из всех, кроме последний!
Есть два основных варианта - malloc перед циклом (или просто использовать массив), если вы знаете размер, который будет работать для всего, или использовать realloc:
char * buffer = NULL;
for (int i = 0; i < num_files; i++) {
buffer = realloc(proper_length(i));
// do some things with buffer
}
free(buffer);
Улучшить обработку. Имейте некоторый псевдокод:
#define BLOCK_SIZE 1024 // or about the bigger size of your strings.
char *buffer = (char *) malloc(BLOCK_SIZE)
for(int i=0; i<20; i++)
{
while (more bytes left to read)
{
read full string or BLOCK_SIZE bytes at max // most calls work this way
proces bytes in buffer
}
}
free(buffer);