2011-11-09 15 views
5

Sto lavorando a un'applicazione di telefonia SIP abbastanza grande e occasionalmente quando usiamo l'interfaccia utente web integrata (scritta usando tntnet) sotto carico di chiamate pesanti, il programma uscirà a causa di uno std: : gettato male. Ci sono centinaia di thread in uso (3 per chiamata attiva), quindi la posizione del codice che causa l'eccezione è abbastanza casuale ma è sempre dopo aver usato la GUI.Altri possibili motivi per std :: bad_alloc che viene generato

Ora, capisco che std :: bad_alloc può essere lanciato quando si esaurisce la memoria, il che non è il caso in questa situazione. Penso anche che possa essere lanciato quando c'è la corruzione dell'heap, che sto ancora cercando dove possa trovarsi nella base del codice.

Ma la mia domanda è, ci sono altri motivi per cui std :: bad_alloc verrà gettato a parte dalla memoria o dalla corruzione dell'heap? Sto usando GNU g ++ su Linux.

+0

allocatori personalizzati in uso? – sehe

+0

Non che io sappia o abbia visto. –

+0

bad_alloc viene lanciato solo per l'errore di allocare memoria, anche se come si nota, se il programma esegue qualcosa di indefinito, potrebbe fare qualsiasi cosa, incluso lanciare bad_alloc in qualsiasi momento dopo l'azione indefinita –

risposta

5

Molto probabilmente, hai davvero esaurito la memoria. Sarebbe un bug di corruzione dell'heap estremamente raro che ha causato in modo consistente il solo a bad_alloc. Sarebbe come scribacchiare con precisione chirurgica.

È possibile che ci sia semplicemente un bug nel codice che alloca una quantità enorme di memoria. Ma ti aspetteresti che l'eccezione venga lanciata, almeno in una grande parte del tempo, in quel codice. Il fatto che l'eccezione provenga da un certo numero di luoghi diversi pesa su questo.

La frammentazione grave può causare un problema, in particolare per le piattaforme con scarse implementazioni di malloc. È raro, ma succede.

Una cosa che farei immediatamente: rilevare l'eccezione e richiamare una funzione che salva una copia di /proc/self/maps. Questo ti darà una buona idea dell'uso massimo della memoria del processo. Puoi giudicare se è vicino a qualsiasi piattaforma, politica o limitazioni hardware.

3

Su Linux il limite di spazio indirizzo corrente può essere utilizzato per limitare artificialmente la quantità di memoria che un processo può utilizzare. È possibile impostare manualmente questo con setrlimit(RLIMIT_AS, ...). Questo può anche essere impostato per un'intera shell in bashrc utilizzando ulimit -v. Questo può anche essere impostato per l'intero sistema in /etc/security/limits.conf. Potrebbe esserci anche una voce/proc/sys per questo da qualche parte, non ne sono sicuro.

Se viene raggiunto il limite di spazio degli indirizzi, il processo genererà un file std :: bad_alloc quando si tenta di allocare più memoria. Su un sistema a 64 bit questa può essere una buona "sicurezza" per assicurarsi che una cattiva applicazione o libreria non scappi con la memoria disponibile e fare in modo che il sistema passi a scambiare o smettere di funzionare del tutto. Assicurati che il programma non lo imposti da qualche parte, e assicurati che il resto dell'ambiente non lo abbia impostato. Puoi semplicemente inserire del codice nel bel mezzo del programma da qualche parte per chiamare getrlimit(RLIMIT_AS, ...) per essere sicuro che non si sia intrufolato da qualche parte.

Una causa forse più comune (a parte la mancanza di memoria, ovviamente) è un caso intero senza segno, in cui un uin32_t o uint64_t viene utilizzato per allocare memoria ma era 0 e ne ha sottratto 1, a un'allocazione di richieste molto grande (in 64 bit che sarebbero molte migliaia di petabyte).

In ogni caso, i metodi migliori per rintracciare questo sono con GDB. Se la tua applicazione non usa affatto delle eccezioni (e quindi non ha affatto dichiarazioni "catch"), puoi abilitare i file core (ulimit -c unlimited). La prossima volta che il programma si blocca, il sistema operativo genererà un file core e il caricamento in GDB ti darà immediatamente un backtrace che ti mostra dove si è verificato il crash del programma.

Se si dispone di alcuni (ma non molti) luoghi in cui viene utilizzato try e di questi allocazioni errati, oltre a commentarli mentre si esegue il debug di questo problema, è possibile eseguire l'applicazione in GDB e utilizzare il comando catch throw per fare in modo che GDB si interrompa ogni volta che viene generata un'eccezione. Affinché uno di questi funzioni, non compilare mai con e compilare sempre (anche quando si utilizza -O3) con -ggdb.

Problemi correlati