URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 1643
[ Назад ]

Исходное сообщение
"malloc/free in threads утечка памяти"

Отправлено SaneK , 25-Апр-03 12:22 

Есть приложение, написанное на Си, использующее нити, работает по следующей схеме:

  При запуске приложения запускается основной поток далее по возникновению какого то события из этого потока запускаются другие потоки использующие одну глобальную переменную, память под которую выделяется malloc'ом в основном потоке и освобождается free в потоках которые запускаются из основного. Доступ к этой переменной разделяется с помощью мьютексов. Вроде прога работает, все нормально, но вот только память используемая ей все время растет (top'ом смотрю).

Подскажите в чем может быть причина?

Спасибо.


Содержание

Сообщения в этом обсуждении
"malloc/free in threads утечка памяти"
Отправлено SaneK , 25-Апр-03 13:10 
Да, забыл, все это дело крутится на FreeBSD 4.6.2



"malloc/free in threads утечка памяти"
Отправлено David , 07-Май-03 22:17 
Покажите код, хотя бы те участки (только не одну строку), где выделяется и освобождается память. Иначе вам вряд ли кто-нить сможет помочь :)

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


"malloc/free in threads утечка памяти"
Отправлено SaneK , 13-Май-03 17:06 
Код примерно такой.
  
*****************************************
//Основной поток

    typedef struct
                {
                 int Поле;
                }pkt;

.........
  //packet  - Глобальная переменная

  packet = (pkt *)calloc(Размер массива,sizeof(pkt));
  i = 0;
  while(1) {

....

Заполняем packet (packet[i].Поле = i)

....

               if (i == Размер массива)
                 {
                 pthread_attr_init(&attr);
                 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
//db_storage_thread - Глобальная переменная                
                 pthread_create (&db_storage_thread, &attr,&my_proccess, (void *)packet);

              pthread_detach(db_storage_thread);

              packet = (pkt *)calloc(Размер массива,sizeof(pkt));
              
              i = 0;
                 }else{


                    i++;
                       }

           } /* End while */

******************************************
//my_proccess

void my_proccess(pkt *packet)
{

  for (i=0;i < Размер массива; i++)
       {
      
     ......

      Что то делаем с packet (сладываем каждый packet[i].поле в файл)
    
     ......
  
     }

free(packet);
  
}

******************************

Происходит наверное именно так т.е. дочерний поток не успевает освободить память до того как основной ее заново выделит. Как такого избежать? Использовать realloc?


"malloc/free in threads утечка памяти"
Отправлено SaneK , 13-Май-03 17:08 
Забыл, pkt - глобальная

"malloc/free in threads утечка памяти"
Отправлено David , 13-Май-03 18:22 
realloc тут не поможет.

самое лучшее решение - изменить дизайн программы, как уже советовал NL.

Другое трудно предложить - трудно представить что может происходить, когда несколько потоков работают с одним куском памяти, один из них освобождает эту память, а другие при этом ничего не ведают. Очень странно, что программа вообще работает, не вылетая по segmentation fault.


"malloc/free in threads утечка памяти"
Отправлено Olej , 14-Май-03 18:32 
Было что-то такое...

>void my_proccess(pkt *packet) {

- вот здесь нужно было бы:
1. заблокироваться на каком-то механизме синхронизации, напр. на критическрй секции (с вызывающей программой);
2. сделать копию *packet - не указателя, а всей структуры...
3. снять блокировку, и уже можно free ... уже не нужно.
4. для всего этого лучше при запуске определить в attr повышенный приоритет потока...

>
>  for (i=0;i < Размер массива; i++)
>       {
>
>     ......
>
>      Что то делаем с packet (сладываем
>каждый packet[i].поле в файл)
>
>     ......
>
>     }
>
>free(packet);

- а вот здесь хорошо бы посмотреть (проанализировать) код завершения free, она же не void ... вообще проверка всех кодов завершения, до уровня параноидальности ;-) - хорошая привычка.

Хотя реализация эта вся - безусловно плохая.
Почему вызывающая программа не могла бы создавать копию *packet для каждого порождаемого потока, например?


"malloc/free in threads утечка памяти"
Отправлено SaneK , 15-Май-03 12:27 
В том то и дело что блокироваться с вызывающем программой нельзя. Основной цикл (в котором потоки порождаются) должен продолжаться без остановки.

>Почему вызывающая программа не могла бы создавать копию *packet для каждого порождаемого потока, например?
А как это реализовать (без остановки основного цикла)в данном случае я что то не пойму.


"malloc/free in threads утечка памяти"
Отправлено Olej , 16-Май-03 11:51 
>В том то и дело что блокироваться с вызывающем программой нельзя. Основной
>цикл (в котором потоки порождаются) должен продолжаться без остановки.

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

Вопрос всегда в том - на сколько блокироваться? на 1мксек, 1мсек, 1сек... А дополнительное (ко времени создания thread-а) время копирования блока параметров ... вряд ли особо существенно.

>>Почему вызывающая программа не могла бы создавать копию *packet для каждого порождаемого потока, например?
>А как это реализовать (без остановки основного цикла)в данном случае я что то не пойму.

Как-то так - в вызывающей программе:
while(1) {
  .... //вот здесь каждый раз выделяется блок параметров
  pkt* packet = (pkt*)calloc(Размер массива,sizeof(pkt));
  // никаких глобальных переменных... и заполняется...
  pthread_create (&db_storage_thread, &attr,&my_proccess, (void *)packet);
  ...

а в функции потока:
void my_proccess( pkt* packet ) {
  ......
  Что то делаем с packet
  free( packet );
}

но ещё лучше - я бы сразу делал дубликат блока параметров - уничтожал переданный блок, а потом что-то делал с дубликатом:
void my_proccess( pkt* packet ) {
  pkt dubl( *packet );
  free( packet );
  ......
  Что то делаем с dubl
}

Обр. вним. - это решение тоже упрощённое, и имеет дефекты синхронизации (об этом и обсуждалось в тех URL, которые я писал) - но оно уже гораздо лучше.


"malloc/free in threads утечка памяти"
Отправлено SaneK , 16-Май-03 12:52 
>но ещё лучше - я бы сразу делал дубликат блока параметров - уничтожал переданный блок, а потом что-то делал с дубликатом:
>void my_proccess( pkt* packet ) {
>  pkt dubl( *packet );
>  free( packet );
>  ......
>  Что то делаем с dubl
>}

Спасибо! Вроде помогло. Но только один момент:

не

pkt dubl(*packet);

а

pkt *dubl=packet;

Еще раз спасибо!


"malloc/free in threads утечка памяти"
Отправлено SaneK , 16-Май-03 12:55 
Вопрос в догонку. Если я вместо такой реализации массива сделаю линейный список, плюс в скорости получу?

"malloc/free in threads утечка памяти"
Отправлено Olej , 16-Май-03 17:55 
>Вопрос в догонку. Если я вместо такой реализации массива сделаю линейный список,
>плюс в скорости получу?

Нет, получите "минус", достаточно значительный ... я думаю.
Смотрите STL - vector - вот с ним можете получить и динамичность, и скорость...
Но это - C++!.
Хотя gcc - до фени - вопрос вкуса юзера ;-)


"malloc/free in threads утечка памяти"
Отправлено Olej , 16-Май-03 15:16 
>>но ещё лучше - я бы сразу делал дубликат блока параметров - уничтожал переданный блок, а потом что-то делал с дубликатом:
>>void my_proccess( pkt* packet ) {
>>  pkt dubl( *packet );
>>  free( packet );
>>  ......
>>  Что то делаем с dubl
>>}
>
>Спасибо! Вроде помогло. Но только один момент:
>
>не
>
> pkt dubl(*packet);
>

>
> pkt *dubl=packet;
>
>Еще раз спасибо!
>

Если у вас есть конструктор по-умолчанию для структуры pkt - а он всегда есть ... если вы не испортили сами, руками - то и 1-е - сработает.

Правда ... подумалось ... это всё в терминологии C++, я в ней имел в виду.


"malloc/free in threads утечка памяти"
Отправлено NL , 08-Май-03 11:30 
1) лучше писать прогу так: трэд, который выделил себе блок памяти, его же и освобожддает, а не поручать free другим трэдам. Так проще  отследить, что откуда берется да и код становится понятнее и путаницы меньше.
2) используй realloc в основном трэде и тогда в остальных трэдах free можно выкинуть

"malloc/free in threads утечка памяти"
Отправлено Olej , 14-Май-03 19:25 
>1) лучше писать прогу так: трэд, который выделил себе блок памяти, его
>же и освобожддает, а не поручать free другим трэдам. Так проще
> отследить, что откуда берется да и код становится понятнее и
>путаницы меньше.

С блоком параметров запуска thread (то, что показано в мсходном коде) - это обычно не проходит, особенно, если thread не join, да и там ... тягомутина. Так что эта задача: синхронизация доступа и разрушения блока параметров - совсем не такая частная, и возникает...

Посмотрите здесь:
http://qnx.org.ru/forum/viewtopic.php?topic=266&forum=4&star...
http://qnx.org.ru/forum/viewtopic.php?topic=1376&forum=4
- может на что натолкнёт...



"malloc/free in threads утечка памяти"
Отправлено Olej , 19-Май-03 17:01 
>  При запуске приложения запускается основной поток далее по возникновению какого
>то события из этого потока запускаются другие потоки использующие одну глобальную
>переменную, память под которую выделяется malloc'ом в основном потоке и освобождается
>free в потоках которые запускаются из основного. Доступ к этой переменной
>разделяется с помощью мьютексов. Вроде прога работает, все нормально, но вот
>только память используемая ей все время растет (top'ом смотрю).

Вот, нашёл случайно - детальное обсуждение синхронизации ровно для того частого случая, который обсуждается: выделение блока параметров и передача его detached thread, который его и освобождает:
http://qnx.org.ru/forum/viewtopic.php?topic=928&forum=4