Насколько плохо продолжать вызывать malloc () и free ()? - PullRequest
18 голосов
/ 30 сентября 2011

Я отправляю текстовый файл - клиент-сервер разбивает текст на пакеты по 512 байт, но некоторые пакеты содержат текст меньше максимального размера, поэтому на стороне сервера при получении каждого пакета я вызываю malloc () для сборкиснова строка, это плохая практика?лучше ли сохранить рабочий буфер, который может соответствовать максимальной длине и продолжать итерацию, копировать и перезаписывать его значения?

хорошо, @nm вот код, это если внутри цикла for (;;) разбудилипо выбору ()

if(nbytes==2) {
            packet_size=unpack_short(short_buf);
            printf("packet size is %d\n",packet_size);
            receive_packet(i,packet_size,&buffer);
            printf("packet=%s\n",buffer);
            free(buffer);
}
//and here is receive_packet() function 
int receive_packet(int fd,int p_len,char **string) {
 *string = (char *)malloc(p_len-2); // 2 bytes for saving the length    
 char *i=*string;   
 int temp;
 int total=0;
 int remaining=p_len-2;
 while(remaining>0) {
     //printf("remaining=%d\n",remaining);
     temp = recv(fd,*string,remaining,0);
     total+=temp;
     remaining=(p_len-2)-total;
     (*string) += temp;
 }
 *string=i;
 return 0;
 }

Ответы [ 7 ]

16 голосов
/ 30 сентября 2011

В вашем примере ваша функция уже содержит системный вызов, поэтому относительная стоимость malloc / free будет практически неизмеримой. В моей системе malloc / free «туда-обратно» в среднем составляет около 300 циклов, а системные вызовы самые дешевые (получение текущего времени, pid и т. Д.) Стоят как минимум 2500 циклов. Ожидайте, что recv будет стоить в 10 раз дороже, и в этом случае стоимость выделения / освобождения памяти будет составлять не более 1% от общей стоимости этой операции.

Конечно, точное время будет варьироваться, но приблизительные порядки величины должны быть довольно инвариантными для разных систем. Я бы даже не стал рассматривать удаление malloc / free как оптимизацию, за исключением функций, которые являются чисто пользовательским пространством. Там, где, вероятно, на самом деле более ценно обходиться без динамического выделения, это операции, в которых не должно быть случаев сбоя - здесь значение состоит в том, что вы упрощаете и укрепляете кодирование, не беспокоясь о что делать, если malloc не удается.

7 голосов
/ 30 сентября 2011

С вызовом malloc и free связаны накладные расходы. Блок должен быть выделен из кучи и помечен как используемый, когда вы освобождаетесь, случается прозорливость. Не зная, какую ОС или компилятор вы используете, это может быть в библиотеке c или на уровне управления памятью ОС. Так как вы выполняете много malloc и освобождаете, вы можете серьезно фрагментировать свою кучу, где у вас может не хватить непрерывной свободной памяти для выполнения malloc в другом месте. Если вы можете выделить только один буфер и продолжать его повторное использование, это, как правило, будет быстрее и с меньшей опасностью фрагментации кучи.

4 голосов
/ 30 сентября 2011

Я обнаружил, что malloc, realloc и free довольно дороги. Если вы можете избежать malloc, лучше повторно использовать уже имеющуюся память.

Edit:
Похоже, я ошибаюсь из-за того, насколько дорогой malloc. Некоторые временные тесты с библиотекой GNU C версии 2.14 для Linux показывают, что для теста, который зацикливается 100 000 раз и выделяет и освобождает 512 слотов со случайными размерами от 1 до 163840 байт:

tsc average loop = 408
tsc of longest loop = 294350

Таким образом, тратить 408 циклов, делая malloc или new в тесном внутреннем цикле, было бы глупо. Кроме этого, не беспокойтесь об этом.

2 голосов
/ 24 мая 2018

Malloc, как правило, довольно недорогой. Это только дорого, если он генерирует системный вызов, чтобы получить больше места в куче. Например, в UNIX-подобных системах в конечном итоге будет сгенерирован вызов sbrk, который будет дорогим. Если вы постоянно используете malloc и освобождаете один и тот же объем памяти, это быстро сойдет с ума. Например, рассмотрим следующую небольшую тестовую программу:

#include <stdlib.h>


int main()
{
  int i=0;
  int *ptr;

  for(int i=0; i<1e6; i++) {
    ptr = malloc(1024*sizeof(int));
    free(ptr);
  }
}

Он выделяет 1024 целых числа и освобождает их и делает это миллион раз. Запустив это на моей довольно скромной машине Linux, превращенной в Linux, я получаю время, которое выглядит так:

time ./test

real    0m0.125s
user    0m0.122s
sys     0m0.003s

Теперь, если я закомментирую malloc и свободную часть цикла, я получу следующее время:

time ./test

real    0m0.009s
user    0m0.005s
sys 0m0.005s

Итак, вы видите, что у malloc и free есть накладные расходы, хотя я думаю, что превышение накладных расходов на бездействие более чем в десять раз ужасно много накладных расходов.

Это особенно быстро, если он может просто продолжать многократно использовать один и тот же кусок кучи (как здесь). Конечно, если бы я продолжал многократно выделять и расширять программу, это заняло бы больше времени, потому что это привело бы к нескольким системным вызовам.

Конечно, ваш пробег может варьироваться в зависимости от ОС, компилятора и реализации stdlib.

1 голос
/ 30 сентября 2011

Измерьте производительность двух решений. Либо путем профилирования или измерения пропускной способности. Невозможно сказать что-либо наверняка.

1 голос
/ 30 сентября 2011

Вызов нескольких malloc / free может фактически увеличить объем памяти, используемой вашим процессом (без каких-либо утечек), если размер, передаваемый в malloc, является переменным, что подтверждается этим вопросом:

C-программаиспользование памяти - больше памяти сообщается, чем выделено

Так что подход с одним буфером, вероятно, лучше.

1 голос
/ 30 сентября 2011

Только тестирование может сказать. При программировании на C я допускаю ошибку, избегая malloc, поскольку утечки памяти могут быть довольно трудно исправить, если вы случайно их создадите.

...