Jump to content

    
Sign in to follow this  
Quasar

Завершение потока в pthreads

Recommended Posts

Есть приложение, использующее pthread, по ходу выполнения приложения создаются новые потоки, выполнив свою работу они завершаются, делая просто return NULL. Я решил посмотреть, сколько памяти использует мое приложение cat /tmp/PID/status и чего-то не понял:

 

 

Name:   app
State:  S (sleeping)
Tgid:   12718
Pid:    12718
PPid:   1
TracerPid:      0
Uid:    0       0       0       0
Gid:    0       0       0       0
FDSize: 32
Groups: 
VmPeak:    93568 kB
VmSize:    93568 kB
VmLck:         0 kB
VmHWM:      1184 kB
VmRSS:      1184 kB
VmData:    90304 kB
VmStk:       136 kB
VmExe:       136 kB
VmLib:      2796 kB
VmPTE:        32 kB
VmSwap:        0 kB
Threads:        10

 

 

VmData с запуском нового потока только растет, и не уменьшается по его завершению, я так понимаю, что память выделенная под стек не освобождается. Это нормально или я неверно интерпретирую полученные данные?

 

Плата вот эта.

 

uname -a
Linux buildroot 2.6.36-rc6 #732 Wed Jun 29 06:03:40 EDT 2011 armv5tejl GNU/Linux

 

 

 

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites
Есть приложение, использующее pthread, по ходу выполнения приложения создаются новые потоки, выполнив свою работу они завершаются, делая просто return NULL.

А завершаете их правильно?

 

Share this post


Link to post
Share on other sites
А завершаете их правильно?

Собственно так и завершаю:

static void *rx_thread ( void *ptr ) {
    .
    .
    .
    return NULL;
}

 

Можно делать pthread_exit(), но я разницы не заметил.

Да, я поглядел /proc/meminfo, свободная память вроде не уменьшается, то есть все таки нормально освобождается все, но мне не ясно, а что же это тогда за виртуальная память и почему она только растет?

cat /proc/meminfo
MemTotal:          60568 kB
MemFree:           40236 kB
Buffers:              16 kB
Cached:             9920 kB
SwapCached:            0 kB
Active:             8132 kB
Inactive:           2952 kB
Active(anon):       1148 kB
Inactive(anon):       12 kB
Active(file):       6984 kB
Inactive(file):     2940 kB
Unevictable:           0 kB
Mlocked:               0 kB
SwapTotal:             0 kB
SwapFree:              0 kB
Dirty:                 8 kB
Writeback:             0 kB
AnonPages:          1164 kB
Mapped:             1816 kB
Shmem:                12 kB
Slab:               4640 kB
SReclaimable:       2200 kB
SUnreclaim:         2440 kB
KernelStack:         400 kB
PageTables:          280 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:       30284 kB
Committed_AS:     184108 kB
VmallocTotal:     956416 kB
VmallocUsed:      266276 kB
VmallocChunk:     686076 kB

Share this post


Link to post
Share on other sites

За потребление стека отвечает VmStk, за общее потребление физической памяти (приватный сет) - VmHWM и VmRSS, пик и текущее соответственно. VmData - это количество виртуальной памяти под данные. Растет обычно из-за хипа, его алгоритм так просто витруальную память не возвращает (из-за соображений производительности). По идее, если тест запустить надолго, рост должен остановиться на некотором значении. А для уменьшения VmData придется играть с низкоуровневыми функциями типа brk/sbrk, что является плохой идеей.

 

Главное, чтобы VmHWM не рос неограниченно.

Share this post


Link to post
Share on other sites
А завершаете их правильно?

 

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

Чтобы освободить эту память, требуется вызывать pthread_join() из какого-либо другого потока.

 

Можно создавать потоки, которые будут удаляться автоматически. Для этого надо указывать атрибут PTHREAD_CREATE_DETACHED при создании потока. По умолчанию он не указан.

Share this post


Link to post
Share on other sites
Можно делать pthread_exit(), но я разницы не заметил.

 

если в потоке зарегистрировать:

 

pthread_cleanup_push(thread_exit_func, (void*)&xxxx);

....

pthread_cleanup_pop(1);

 

функцию для "уборки мусора":

 

void thread_exit_func (void * arg)

{

xxxx_type *xxxx = (thread_params *)arg;

.....

}

 

то завершать поток нужно именно по pthread_exit() - это гарантирует вызов "уборщика", а по return оно не вызывается

Share this post


Link to post
Share on other sites
VmData с запуском нового потока только растет, и не уменьшается по его завершению, я так понимаю, что память выделенная под стек не освобождается. Это нормально или я неверно интерпретирую полученные данные?

Посмотрите вывод команды pmap <PID> - там должно быть хорошо видно, что за блоки памяти выделяются процессом.

 

Вы создаете detached threads или нет? Если нет, Вы в порождающем потоке выполняете pthread_join()?

Если тоже нет, то ИМХО у Вас будет, как минимум, в памяти оставаться стек каждого отработавшего потока.

Чтобы стек освобождался, Вы должны либо "открепить" созданный поток (выполнить pthread_detach(thr)), либо отслеживать его завершение в родительском потоке и выполнять pthread_join().

Как будет завершаться поток (через вызов pthread_exit() или через return NULL) значения не имеет.

Share this post


Link to post
Share on other sites
Посмотрите вывод команды pmap <PID> - там должно быть хорошо видно, что за блоки памяти выделяются процессом.

 

Вы создаете detached threads или нет? Если нет, Вы в порождающем потоке выполняете pthread_join()?

Если тоже нет, то ИМХО у Вас будет, как минимум, в памяти оставаться стек каждого отработавшего потока.

Чтобы стек освобождался, Вы должны либо "открепить" созданный поток (выполнить pthread_detach(thr)), либо отслеживать его завершение в родительском потоке и выполнять pthread_join().

Как будет завершаться поток (через вызов pthread_exit() или через return NULL) значения не имеет.

 

Я всегда жду удаления потоков pthread_join'ом. Вывод pmap не понял. В total он пишет, что использовано 270000 KByte, у меня всего 64МБайт, что это за пространство?

 

 

 pmap 1111 -x
1111: {no such process} /usr/bin/app -c /root/config.ini
Address   Kbytes     PSS   Dirty    Swap  Mode  Mapping
00008000      92      80       0       0  r-xp  /usr/bin/app
00027000       4       4       4       0  rwxp  /usr/bin/app
00028000     132      52      52       0  rwxp  [heap]
4000d000       4       4       4       0  rwxp    [ anon ]
4000e000      28      12       0       0  r-xp  /lib/librt-2.15.so
40015000      28       0       0       0  ---p  /lib/librt-2.15.so
4001c000       4       4       4       0  r-xp  /lib/librt-2.15.so
4001d000       4       4       4       0  rwxp  /lib/librt-2.15.so
40025000      20       4       0       0  r-xp  /usr/lib/libjson.so.0.0.1
4002a000      32       0       0       0  ---p  /usr/lib/libjson.so.0.0.1
40032000       4       4       4       0  rwxp  /usr/lib/libjson.so.0.0.1
40052000       4       4       4       0  rwxp    [ anon ]
40059000       4       4       4       0  rwxp    [ anon ]
40076000     128      17       0       0  r-xp  /lib/libgcc_s.so.1
40096000      28       0       0       0  ---p  /lib/libgcc_s.so.1
4009d000       4       4       4       0  rwxp  /lib/libgcc_s.so.1
400a3000      24      24       0       0  r-xp  /usr/lib/libao.so.4.0.0
400a9000      28       0       0       0  ---p  /usr/lib/libao.so.4.0.0
400b0000       4       4       4       0  rwxp  /usr/lib/libao.so.4.0.0
400b9000       4       4       4       0  rwxp    [ anon ]
400cf000      16       2       0       0  r-xp  /lib/libdl-2.15.so
400d3000      28       0       0       0  ---p  /lib/libdl-2.15.so
400da000       4       4       4       0  r-xp  /lib/libdl-2.15.so
400db000       4       4       4       0  rwxp  /lib/libdl-2.15.so
400dd000       8       8       0       0  r-xp  /usr/lib/ao/plugins-4/libpulse.so
400df000      28       0       0       0  ---p  /usr/lib/ao/plugins-4/libpulse.so
400e6000       4       4       4       0  rwxp  /usr/lib/ao/plugins-4/libpulse.so
400f6000     136      13       0       0  r-xp  /lib/ld-2.15.so
40118000       4       4       4       0  rwxp    [ anon ]
4011f000       4       4       4       0  r-xp  /lib/ld-2.15.so
40120000       4       4       4       0  rwxp  /lib/ld-2.15.so
40121000       8       8       0       0  r-xp  /usr/lib/ao/plugins-4/liboss.so
40123000      32       0       0       0  ---p  /usr/lib/ao/plugins-4/liboss.so
4012b000       4       4       4       0  rwxp  /usr/lib/ao/plugins-4/liboss.so
4012c000      20      16       0       0  r-xp  /usr/lib/ao/plugins-4/libalsa.so
40131000      28       0       0       0  ---p  /usr/lib/ao/plugins-4/libalsa.so
40138000       4       4       4       0  rwxp  /usr/lib/ao/plugins-4/libalsa.so
40146000      12       8       0       0  r-xp  /usr/lib/libpulse-simple.so.0.0.3
40149000      28       0       0       0  ---p  /usr/lib/libpulse-simple.so.0.0.3
40150000       4       4       4       0  rwxp  /usr/lib/libpulse-simple.so.0.0.3
40182000      84      38       0       0  r-xp  /lib/libpthread-2.15.so
40197000      28       0       0       0  ---p  /lib/libpthread-2.15.so
4019e000       4       4       4       0  r-xp  /lib/libpthread-2.15.so
4019f000       4       4       4       0  rwxp  /lib/libpthread-2.15.so
401a0000       8       4       4       0  rwxp    [ anon ]
401a2000     788     372       0       0  r-xp  /usr/lib/libstdc++.so.6.0.16
40267000      28       0       0       0  ---p  /usr/lib/libstdc++.so.6.0.16
4026e000      16      16      16       0  r-xp  /usr/lib/libstdc++.so.6.0.16
40272000       8       8       8       0  rwxp  /usr/lib/libstdc++.so.6.0.16
40274000      24       8       8       0  rwxp    [ anon ]
4027a000     624      26       0       0  r-xp  /lib/libm-2.15.so
40316000      32       0       0       0  ---p  /lib/libm-2.15.so
4031e000       4       4       4       0  r-xp  /lib/libm-2.15.so
4031f000       4       4       4       0  rwxp  /lib/libm-2.15.so
40320000    1296     109       0       0  r-xp  /lib/libc-2.15.so
40464000      28       0       0       0  ---p  /lib/libc-2.15.so
4046b000       8       8       8       0  r-xp  /lib/libc-2.15.so
4046d000       4       4       4       0  rwxp  /lib/libc-2.15.so
4046e000      12      12      12       0  rwxp    [ anon ]
40471000       4       0       0       0  ---p    [ anon ]
40472000    8188       8       8       0  rwxp    [ anon ]
40c71000     264     122       0       0  r-xp  /usr/lib/libpulse.so.0.14.3
40cb3000      28       0       0       0  ---p  /usr/lib/libpulse.so.0.14.3
40cba000       4       4       4       0  rwxp  /usr/lib/libpulse.so.0.14.3
40cbb000     304     124       0       0  r-xp  /usr/lib/pulseaudio/libpulsecommon-2.1.so
40d07000      28       0       0       0  ---p  /usr/lib/pulseaudio/libpulsecommon-2.1.so
40d0e000       4       4       4       0  rwxp  /usr/lib/pulseaudio/libpulsecommon-2.1.so
40d0f000     328      10       0       0  r-xp  /usr/lib/libsndfile.so.1.0.25
40d61000      32       0       0       0  ---p  /usr/lib/libsndfile.so.1.0.25
40d69000       8       8       8       0  rwxp  /usr/lib/libsndfile.so.1.0.25
40d6b000      16       0       0       0  rwxp    [ anon ]
40d6f000     712     136       0       0  r-xp  /usr/lib/libasound.so.2.0.0
40e21000      32       0       0       0  ---p  /usr/lib/libasound.so.2.0.0
40e29000      16      16      16       0  rwxp  /usr/lib/libasound.so.2.0.0
40e2d000       4       0       0       0  ---p    [ anon ]
40e2e000    8188       8       8       0  rwxp    [ anon ]
4164e000       4       0       0       0  ---p    [ anon ]
4164f000    8188       8       8       0  rwxp    [ anon ]
41e4e000       4       0       0       0  ---p    [ anon ]
41e4f000    8188       8       8       0  rwxp    [ anon ]
426d3000       4       0       0       0  ---p    [ anon ]
426d4000    8188       8       8       0  rwxp    [ anon ]
42ed3000       4       0       0       0  ---p    [ anon ]
42ed4000    8188       8       8       0  rwxp    [ anon ]
4376a000       4       0       0       0  ---p    [ anon ]
4376b000    8188       8       8       0  rwxp    [ anon ]
43f6a000       4       0       0       0  ---p    [ anon ]
43f6b000    8188       8       8       0  rwxp    [ anon ]
44812000       4       0       0       0  ---p    [ anon ]
44813000    8188       8       8       0  rwxp    [ anon ]
45012000       4       0       0       0  ---p    [ anon ]
45013000    8188      12      12       0  rwxp    [ anon ]
45902000       4       0       0       0  ---p    [ anon ]
45903000    8188       8       8       0  rwxp    [ anon ]
46200000     132      40      40       0  rwxp    [ anon ]
46221000     892       0       0       0  ---p    [ anon ]
46300000     132      40      40       0  rwxp    [ anon ]
46321000     892       0       0       0  ---p    [ anon ]
46400000       4       0       0       0  ---p    [ anon ]
46401000    8188      20      20       0  rwxp    [ anon ]
46c17000       4       0       0       0  ---p    [ anon ]
46c18000    8188       8       8       0  rwxp    [ anon ]
47417000       4       0       0       0  ---p    [ anon ]
47418000    8188       8       8       0  rwxp    [ anon ]
47c17000       4       0       0       0  ---p    [ anon ]
47c18000    8188      20      20       0  rwxp    [ anon ]
48417000       4       0       0       0  ---p    [ anon ]
48418000    8188       8       8       0  rwxp    [ anon ]
48c17000       4       0       0       0  ---p    [ anon ]
48c18000    8188      20      20       0  rwxp    [ anon ]
49417000       4       0       0       0  ---p    [ anon ]
49418000    8188       8       8       0  rwxp    [ anon ]
49c17000       4       0       0       0  ---p    [ anon ]
49c18000    8188      20      20       0  rwxp    [ anon ]
4a417000       4       0       0       0  ---p    [ anon ]
4a418000    8188       8       8       0  rwxp    [ anon ]
4ac17000       4       0       0       0  ---p    [ anon ]
4ac18000    8188      20      20       0  rwxp    [ anon ]
4b418000       4       0       0       0  ---p    [ anon ]
4b419000    8188      20      20       0  rwxp    [ anon ]
4bc18000       4       0       0       0  ---p    [ anon ]
4bc19000    8188       8       8       0  rwxp    [ anon ]
4c418000       4       0       0       0  ---p    [ anon ]
4c419000    8188       8       8       0  rwxp    [ anon ]
4cc18000       4       0       0       0  ---p    [ anon ]
4cc19000    8188      20      20       0  rwxp    [ anon ]
4d418000       4       0       0       0  ---p    [ anon ]
4d419000    8188       8       8       0  rwxp    [ anon ]
4dc18000       4       0       0       0  ---p    [ anon ]
4dc19000    8188      20      20       0  rwxp    [ anon ]
4e418000       4       0       0       0  ---p    [ anon ]
4e419000    8188       8       8       0  rwxp    [ anon ]
4ec18000       4       0       0       0  ---p    [ anon ]
4ec19000    8188      20      20       0  rwxp    [ anon ]
4f418000       4       0       0       0  ---p    [ anon ]
4f419000    8188       8       8       0  rwxp    [ anon ]
4fc18000       4       0       0       0  ---p    [ anon ]
4fc19000    8188      12      12       0  rwxp    [ anon ]
50480000       4       0       0       0  ---p    [ anon ]
50481000    8188      20      20       0  rwxp    [ anon ]
bef06000     132       8       8       0  rw-p  [stack]
--------  ------  ------  ------  ------
total     270064    1837     708       0

Share this post


Link to post
Share on other sites
Я всегда жду удаления потоков pthread_join'ом. Вывод pmap не понял.

Вот такие группы блоков памяти

4f418000       4       0       0       0  ---p    [ anon ]
4f419000    8188       8       8       0  rwxp    [ anon ]

есть ни что иное как стек потока. pthread выделяет стек двумя кусочками: 4k и все остальное. Я насчитал у Вас 32 дочерних потока со стеками по 8 мегабайт у каждого. Это действительно так?

Если родительский поток вызывает pthread_join, то после завершения дочернего потока выделенная под стек память должна была освободиться.

 

В total он пишет, что использовано 270000 KByte, у меня всего 64МБайт, что это за пространство?

Есть такое понятие как виртуальная память. Что это такое, можно почитать хотя бы тут: http://ru.wikipedia.org/wiki/Виртуальная_память

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

 

Еще обратите внимание на поле Dirty. Если я правильно понимаю, оно показывает объем памяти, реально использованный процессом в данном блоке. Например, в процитированном мной фрагменте видно, что поток использовал 8 кбайт из 8 Мбайт, выделенных ему для стека.

Edited by alx2

Share this post


Link to post
Share on other sites
Если родительский поток вызывает pthread_join, то после завершения дочернего потока выделенная под стек память должна была освободиться.

Небольшое уточнение. Сейчас я провел небольшой эксперимент. В моей реализации libpthread pthread_join() освобождает все стеки кроме пяти последних. Если затем создать 5 новых потоков, они повторно заюзают те блоки, которые остались после завершения предыдущих.

 

Вот тестовая программка, с которой можно все это увидеть:

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

void *child(void *context)
{
   sleep(5);
   return NULL;
}

int main()
{
   // Создаем 30 потоков
   pthread_t thr[30];

   for(int i = 0; i < 30; i++)
       pthread_create(&thr[i], NULL, child, NULL);
   printf("threads created\n");

   // Ждем завершения всех потоков
   for(int i = 0; i < 30; i++)
       pthread_join(thr[i], NULL);
   printf("threads ended\n");
   sleep(5);
   return 0;
}

Сравните карту памяти сразу после запуска и после завершения дочерних потоков.

Попробуйте убрать pthread_join() и Вы увидите, что после завершения всех потоков вся их память остается занятой.

Edited by alx2

Share this post


Link to post
Share on other sites
Я насчитал у Вас 32 дочерних потока со стеками по 8 мегабайт у каждого. Это действительно так?

 

Да, эти потоки реально существуют.

 

По поводу реальной и виртуальной памяти, я в общем в курсе. Я поднял этот вопрос с целью понять, не течет ли у меня память. И из обсуждения не совсем понял, как понять точно, что память течет. То есть, запустить приложения на длительный срок, просмотреть, сколько было выделено, сколько освобождено. С учетом того, что приложение не должно разрастаться по потреблению памяти со временем.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this