PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : pthread_join gibt Speicher nicht frei



Beatkiller
13-09-2008, 22:25
Hallo,

ich rätsel schon seit geraumer Zeit an diesem Problem, und bin mit Sicherheit bereits betriebsblind. Kann mir jemand sagen, was an dem Code falsch sein soll, dass der Speicher mit pthread_join() nicht freigegeben wird?


/*
* main.c
*/
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <string>

#define OWNPID getpid()
#define MAXTHREADS 10

struct threadargs
{
unsigned int id;
std::string first;
std::string last;
};

void *threadfunc(void *args)
{
threadargs *myArgs = (threadargs*)args;
printf("first: %s\n", myArgs->first.c_str());
printf("last: %s\n", myArgs->last.c_str());

pthread_exit((void*)0);
}

void TraceUsage(char *label)
{
pid_t pid;
char comm[30];
char state;
pid_t ppid;
gid_t pgrp;
int session;
int tty;
gid_t tpgid;
unsigned int flags;
unsigned long minflt;
unsigned long cminflt;
unsigned long majflt;
unsigned long cmajflt;
int utime;
int stime;
int cutime;
int cstime;
int counter;
short priority;
unsigned long timeout;
unsigned long itrealvalue;
int starttime;
unsigned long vsize;
unsigned long rss;
unsigned long rlim;
unsigned long startcode;
unsigned long endcode;
unsigned long startstack;
unsigned long kstkesp;
unsigned long kstkeip;
int signal;
int blocked;
int sigignore;
int sigcatch;
unsigned long wchan;

char statpath[30];

sprintf(statpath, "/proc/%d/stat", OWNPID);
FILE *fp = fopen(statpath, "r");

if(fp == NULL)
return;

int r = fscanf(fp,
"%d %s %c %d %d %d %d %d %u %ld %ld %ld %ld %d %d %d %d %d %d %ld %ld %d %ld %ld %ld %ld %ld %ld %ld %ld %d %d %d %d %ld",
&pid, comm, &state, &ppid, &pgrp, &session, &tty, &tpgid, &flags, &minflt, &cminflt,
&majflt, &cmajflt, &utime, &stime, &cutime, &cstime, &counter, &priority, &timeout,
&itrealvalue, &starttime, &vsize, &rss, &rlim, &startcode, &endcode, &startstack,
&kstkesp, &kstkeip, &signal, &blocked, &sigignore, &sigcatch, &wchan
);

fclose(fp);

if(r == 0)
{
return;
}

fprintf(stderr, "%s: rss = %ld, vsize = %ld\n\n", label, rss, vsize);
}

int main(void)
{
pthread_t thread[MAXTHREADS];
char label[10];
unsigned int i;
threadargs targs;
targs.first = "Hello";
targs.last = "World!";

TraceUsage("Init");

for(i = 0; i < MAXTHREADS; i++)
{
targs.id = i;
pthread_create(&thread[i], NULL, threadfunc, (void*)&targs);
pthread_join(thread[i], NULL);
sprintf(label, "%d", i);
TraceUsage(label);
}
}


Es wird folgende Ausgabe erzeugt:


./threadtest
Init: rss = 220, vsize = 2375680

first: Hello
last: World!
0: rss = 234, vsize = 10780672

first: Hello
last: World!
1: rss = 234, vsize = 10780672

first: Hello
last: World!
2: rss = 234, vsize = 10780672

first: Hello
last: World!
3: rss = 234, vsize = 10780672

first: Hello
last: World!
4: rss = 234, vsize = 10780672

first: Hello
last: World!
5: rss = 234, vsize = 10780672

first: Hello
last: World!
6: rss = 234, vsize = 10780672

first: Hello
last: World!
7: rss = 234, vsize = 10780672

first: Hello
last: World!
8: rss = 234, vsize = 10780672

first: Hello
last: World!
9: rss = 234, vsize = 10780672

Wäre toll, wenn mir da jemand weiter helfen könnte.

PS: Ja, ich weiß, man soll C++ Objekte nicht in C-Code einbauen, das war auch nur ein Test, um den Speicher künstlich aufzublähen.

Vincent Vega
14-09-2008, 00:02
Hallo,

ich rätsel schon seit geraumer Zeit an diesem Problem, und bin mit Sicherheit bereits betriebsblind. Kann mir jemand sagen, was an dem Code falsch sein soll, dass der Speicher mit pthread_join() nicht freigegeben wird?


Welcher Speicher soll denn freigegeben werden? pthread_join() wartet, dass ein gegebener Thread beendet wird, sonst nichts. Abgesehen davon benutzt Du pthread_create() und pthread_join() in ziemlich sinnloser Weise: Du erzeugst in Deiner Schlaufe immer einen Thread und wartest sofort danach, dass dieser Thread beendet wird. Das heisst, in Deinem Programm existieren immer nur maximal zwei Threads gleichzeitig. Damit Du 10 Threads gleichzeitig erhältst, musst Du in der ersten Schlaufe die Threads erzeugen und in einer zweiten Schlaufe darauf warten, dass die Threads beendet sind.

Beatkiller
14-09-2008, 08:50
Danke für die Antwort. Ich bin mir im Klaren darüber, dass ich nur einen Kind-Thread habe plus Haupt-Thread. Das war für diesen Proof-of-concept auch genau mein Ziel. Meine Frage war an dieser Stelle, warum der vsize (siehe Ausgabe) nicht zurück auf 2375680 fällt, nach ich mit pthread_join() auf das Ende des Kind-Threads gewartet habe. Das bei Neu-Erzeugung eines Kind-Threads mittels pthread_create() dann kein neuer Speicher angefordert wird, ist ja schon mal was, weil es bedeutet, das der gleiche Speicherbereich für alle Kind-Threads verwendet wird. Ich hätte allerdings erwartet, das nach Beenden des Threads auch der Stack für den Thread freigegeben wird, was offensichtlich nicht der Fall ist.

Ich habe auch schon mit pthread_attr_setdetachstate() den Thread auf PTHREAD_CREATE_DETACHED gesetzt, aber das führt zum gleichen Resultat.

Eine andere Sache ist die Analyse mittels Valgrind oder memprof:


==12691== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 21 from 1)
--12691--
--12691-- supp: 21 Ubuntu-stripped-ld.so
==12691== malloc/free: in use at exit: 68 bytes in 1 blocks.
==12691== malloc/free: 12 allocs, 11 frees, 3,940 bytes allocated.
==12691==
==12691== searching for pointers to 1 not-freed blocks.
==12691== checked 8,511,296 bytes.
==12691==
==12691== 68 bytes in 1 blocks are possibly lost in loss record 1 of 1
==12691== at 0x401BEF5: calloc (vg_replace_malloc.c:397)
==12691== by 0x400EDAB: _dl_allocate_tls (in /lib/ld-2.3.2.so)
==12691== by 0x402C8CA: allocate_stack (in /lib/tls/libpthread-0.34.so)
==12691== by 0x402C587: pthread_create@@GLIBC_2.1 (in /lib/tls/libpthread-0.34.so)
==12691== by 0x804894C: main (main.cpp:112)
==12691==
==12691== LEAK SUMMARY:
==12691== definitely lost: 0 bytes in 0 blocks.
==12691== possibly lost: 68 bytes in 1 blocks.
==12691== still reachable: 0 bytes in 0 blocks.
==12691== suppressed: 0 bytes in 0 blocks.
--12691-- memcheck: sanity checks: 2 cheap, 2 expensive
--12691-- memcheck: auxmaps: 0 auxmap entries (0k, 0M) in use
--12691-- memcheck: auxmaps_L1: 0 searches, 0 cmps, ratio 0:10
--12691-- memcheck: auxmaps_L2: 0 searches, 0 nodes
--12691-- memcheck: SMs: n_issued = 12 (192k, 0M)
--12691-- memcheck: SMs: n_deissued = 0 (0k, 0M)
--12691-- memcheck: SMs: max_noaccess = 65535 (1048560k, 1023M)
--12691-- memcheck: SMs: max_undefined = 0 (0k, 0M)
--12691-- memcheck: SMs: max_defined = 158 (2528k, 2M)
--12691-- memcheck: SMs: max_non_DSM = 12 (192k, 0M)
--12691-- memcheck: max sec V bit nodes: 1 (0k, 0M)
--12691-- memcheck: set_sec_vbits8 calls: 1 (new: 1, updates: 0)
--12691-- memcheck: max shadow mem size: 496k, 0M
--12691-- translate: fast SP updates identified: 3,386 ( 87.6%)
--12691-- translate: generic_known SP updates identified: 234 ( 6.0%)
--12691-- translate: generic_unknown SP updates identified: 244 ( 6.3%)
--12691-- tt/tc: 6,608 tt lookups requiring 6,777 probes
--12691-- tt/tc: 6,608 fast-cache updates, 3 flushes
--12691-- transtab: new 3,130 (67,253 -> 948,035; ratio 140:10) [0 scs]
--12691-- transtab: dumped 0 (0 -> ??)
--12691-- transtab: discarded 6 (153 -> ??)
--12691-- scheduler: 337,679 jumps (bb entries).
--12691-- scheduler: 2/3,710 major/minor sched events.
--12691-- sanity: 3 cheap, 2 expensive checks.
--12691-- exectx: 769 lists, 11 contexts (avg 0 per list)
--12691-- exectx: 44 searches, 33 full compares (750 per 1000)
--12691-- exectx: 0 cmp2, 46 cmp4, 0 cmpAll
--12691-- errormgr: 7 supplist searches, 69 comparisons during search
--12691-- errormgr: 21 errlist searches, 46 comparisons during search


Besonders der non-freed pointer, der in _dl_allocate_tls() erzeugt wird, macht mich etwas stutzig. Was läuft hier falsch? Ist in pthread_create ein memory leak? Google führt mich auch nur zu Seiten, wo diese Thematik behandelt aber nicht vollständig geklärt wird. Arbeitet der Memory-Profiler hier fehlerhaft?