2009-12-14 13 views
10

Valgrind segnala una perdita di memoria quando si assegna un valore a una stringa.Valgrind segnala perdite di memoria durante l'assegnazione di un valore a una stringa

Ho usato il seguente codice semplice per verificare una perdita di memoria riportata da Valgrind.

/****************************************** 
* FILE: t3.c 
* Compiled using : g++ -g t3.c -o t3 
* 
* $ g++ -v 
* Reading specs from /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/specs 
* Configured with: ./configure --prefix=/usr --infodir=/share/info --mandir=/share/man 
*  --enable-languages=c,c++ --with-system-zlib --program-suffix=-3.4 --enable-threads=posix 
* Thread model: posix 
* gcc version 3.4.6 
******************************************/ 


#include <iostream> 
#include <string> 

using namespace std; 

/************************************************************** 
**************************************************************/ 
int main(int argc, char *argv[]) 
{ 
    string test = "XXXXXXXXX"; 
    cout << "this is a test " << test << endl; 
    exit(0); 
} 

compilo con questo comando:

$ g++ -g t3.c -o t3 

E quando corro Valgrind che riporta una perdita di memoria quando si tenta di assegnare un valore a una stringa. Sto usando questo semplice test per indagare su una perdita di memoria nel programma reale, e sembra che l'uso della stringa possa causare qualche tipo di problema.

Da 0x8048A6F: main (t3.c: 23) è la riga: string test = "XXXXXXXXX"; Qualcuno può dare qualche suggerimento su un comportamento così strano?

[[email protected]101222 C]$ valgrind --leak-check=full ./t3 
==3910== Memcheck, a memory error detector. 
==3910== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al. 
==3910== Using LibVEX rev 1732, a library for dynamic binary translation. 
==3910== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP. 
==3910== Using valgrind-3.2.3, a dynamic binary instrumentation framework. 
==3910== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al. 
==3910== For more details, rerun with: -v 
==3910== 
this is a test XXXXXXXXX 
==3910== 
==3910== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 25 from 1) 
==3910== malloc/free: in use at exit: 102 bytes in 3 blocks. 
==3910== malloc/free: 4 allocs, 1 frees, 126 bytes allocated. 
==3910== For counts of detected errors, rerun with: -v 
==3910== searching for pointers to 3 not-freed blocks. 
==3910== checked 194,136 bytes. 
==3910== 
==3910== 16 bytes in 1 blocks are definitely lost in loss record 1 of 3 
==3910== at 0x4017846: malloc (m_replacemalloc/vg_replace_malloc.c:149) 
==3910== by 0x4018E05: realloc (m_replacemalloc/vg_replace_malloc.c:306) 
==3910== by 0x41B441A: argz_append (in /lib/libc-2.2.5.so) 
==3910== by 0x41593B9: __newlocale (in /lib/libc-2.2.5.so) 
==3910== by 0x40E010B: std::locale::facet::_S_create_c_locale(__locale_struct*&, char const*, __locale_struct*) (c++locale.cc:99) 
==3910== by 0x407EF6F: std::locale::facet::_S_initialize_once() (../../.././libstdc++-v3/src/locale.cc:172) 
==3910== by 0x407EFB4: std::locale::facet::_S_get_c_locale() (../../.././libstdc++-v3/src/locale.cc:185) 
==3910== by 0x407A422: std::ctype<char>::ctype(unsigned short const*, bool, unsigned) (/usr3/BUILD/gcc/gcc-3.4.6/i686-pc-linux-gnu/libstdc++-v3/include/i686-pc-linux-gnu/bits/ctype_noninline.h:104) 
==3910== by 0x40801D5: std::locale::_Impl::_Impl(unsigned) (/usr3/BUILD/gcc/gcc-3.4.6/libstdc++-v3/libsupc++/new:92) 
==3910== by 0x4080EED: std::locale::_S_initialize_once() (/usr3/BUILD/gcc/gcc-3.4.6/libstdc++-v3/libsupc++/new:92) 
==3910== by 0x4080F84: std::locale::_S_initialize() (../../.././libstdc++-v3/src/locale_init.cc:155) 
==3910== by 0x4080FE7: std::locale::locale() (../../.././libstdc++-v3/src/locale_init.cc:102) 
==3910== 
==3910== 
==3910== 22 bytes in 1 blocks are possibly lost in loss record 2 of 3 
==3910== at 0x4017C38: operator new(unsigned) (m_replacemalloc/vg_replace_malloc.c:163) 
==3910== by 0x40BF2C4: std::string::_Rep::_S_create(unsigned, unsigned, std::allocator<char> const&) (/usr3/BUILD/gcc/gcc-3.4.6/i686-pc-linux-gnu/libstdc++-v3/include/ext/new_allocator.h:81) 
==3910== by 0x40C1CE4: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (/usr3/BUILD/gcc/gcc-3.4.6/i686-pc-linux-gnu/libstdc++-v3/include/bits/basic_string.tcc:150) 
==3910== by 0x40C1E15: std::string::string(char const*, std::allocator<char> const&) (/usr3/BUILD/gcc/gcc-3.4.6/i686-pc-linux-gnu/libstdc++-v3/include/bits/basic_string.h:1386) 
==3910== **by 0x8048A6F: main (t3.c:23)** 
==3910== 
==3910== LEAK SUMMARY: 
==3910== definitely lost: 16 bytes in 1 blocks. 
==3910==  **possibly lost: 22 bytes in 1 blocks.** 
==3910== still reachable: 64 bytes in 1 blocks. 
==3910==   suppressed: 0 bytes in 0 blocks. 
==3910== Reachable blocks (those to which a pointer was found) are not shown. 
==3910== To see them, rerun with: --leak-check=full --show-reachable=yes 
[[email protected] C]$ 

risposta

43

Perché si chiamano exit(0), in modo che il distruttore stringa non viene richiamato. Basta usare return 0.

Per elaborare, il costruttore di std::string alloca memoria heap per memorizzare la stringa, facendo affidamento sul distruttore per deallocare quella memoria. Se dichiari un oggetto stringa nello stack, il distruttore verrà richiamato automaticamente quando l'oggetto stringa esce dall'ambito, liberando così la memoria. Ma exit è davvero un meccanismo C; esce immediatamente dal programma senza eseguire il significato di stack-unwinding che i distruttori C++ per gli oggetti stack locali non verranno chiamati.

3

Se si allocano cinque stringhe, si ottiene una perdita di memoria cinque volte superiore o se è sempre la stessa quantità? Se è la stessa quantità, probabilmente non hai alcuna perdita. Alcune librerie allocano memoria per contabilità interna/efficienza/eccetera che non viene rilasciata fino a dopo che valgrind smette di cercare. Questi vengono rilevati come perdite di memoria perché il programma ha causato l'assegnazione ma non ha mai causato una deallocazione. Se è cinque volte l'importo, allora l'implementazione della stringa potrebbe essere errata. Sono d'accordo con Charles Salvia però ... riprova con return 0; invece di exit(0); e vedi se questo cambia qualcosa.

3

In una delle mie lezioni di informatica, ci è stato detto che Valgrind fornisce informazioni su stringhe di cui non dovremmo preoccuparci. Ecco il file di soppressione che ci hanno dato per le stringhe: https://sites.google.com/site/complingfiles/files/string.supp

+0

Il link qui menzionato purtroppo non funziona più. – Riot

+0

Sì, la scuola ha cambiato classe in java. Vedrò se riesco a scavare ovunque. –

+1

@Riot: trovato il file e pubblicato un nuovo collegamento. –

2

Pur avendo alcun exit(0) alla fine del programma ho avuto problema simile con i falsi positivi con std::string. Stavo collegando staticamente con libstdc++. La commutazione dell'opzione di collegamento per condividere e compilare con GLIBCXX_FORCE_NEW sopprime gli avvisi.

+0

Grazie, grazie, grazie, grazie! –

+0

Sembra che la compilazione con il flag 'GLIBCXX_FORCE_NEW' in realtà non faccia nulla. Secondo [libstdC++ docs per mt_allocator] (https://gcc.gnu.org/onlinedocs/libstdc++/manual/mt_allocator_impl.html), è una variabile di ambiente. "Se la variabile di ambiente GLIBCXX_FORCE_NEW è impostata, imposta il valore bool _S_force_new su true e quindi restituisce.". Quindi, fai semplicemente qualcosa come "export GLIBCXX_FORCE_NEW = 1;" e poi esegui valgrind. Questo ha risolto un sacco di problemi che ho avuto con std :: string dando falsi positivi. – BobTuckerman

Problemi correlati