È una perdita di tempo liberare risorse prima di uscire da un processo? [duplicare]

62

Consideriamo un programma fittizio che costruisce un elenco collegato nell'heap e alla fine del programma c'è un ciclo che libera tutti i nodi e quindi esce. In questo caso, diciamo che l'elenco collegato è solo 500K di memoria e non è richiesta alcuna gestione dello spazio speciale.

  • È una perdita di tempo, perché il sistema operativo lo farà comunque?
  • Ci sarà un comportamento diverso in seguito?
  • È diverso a seconda della versione del sistema operativo?

Sono principalmente interessato ai sistemi basati su UNIX, ma qualsiasi informazione sarà apprezzata. Ho avuto oggi la mia prima lezione sul corso del sistema operativo e ora me lo chiedo.

Modifica: dal momento che molte persone sono preoccupate per gli effetti collaterali, e in generale per la "buona pratica di programmazione" e così via. Hai ragione! Sono d'accordo al 100% con le tue dichiarazioni. Ma la mia domanda è solo ipotetica, voglio sapere come il sistema operativo gestisce questo. Quindi per favore lascia fuori cose come "trovare altri bug quando si libera tutta la memoria".

    
posta Kahil 05.08.2015 - 21:05
fonte

16 risposte

18

OK, ho appena ricevuto un'e-mail dal mio istruttore, con una risposta molto buona e ragionevole. Eccolo:

Hi Ramzi,

Thanks for the link to the interesting messages thread which you started.

As per our discussion, malloc operates on the process' virtual memory. So, when the process dies, its virtual address space "disappears", and any physical memory mapped to it is freed. Hence, disregarding "good software engineering practices" and such, dynamic memory de-allocation just before exiting a process is indeed a waste of time.

(Needless to say, this is not the case when a single thread terminates but other threads of that process keep executing.)

Quindi in base a questo:

  • È una perdita di tempo
  • Non avrà effetti successivi
  • È indipendente dalle versioni del sistema operativo.
risposta data 09.10.2016 - 15:06
fonte
67

Il mio problema principale con il tuo approccio è che uno strumento di rilevamento perdite (come Valgrind) lo segnalerà e inizierai a ignorarlo. Poi, un giorno, si potrebbe verificare una vera perdita, e non lo noterai mai a causa di tutto il rumore.

    
risposta data 19.03.2012 - 16:00
fonte
39

Una volta ho dovuto implementare un algoritmo usando deques che sono stati allocati dinamicamente. Mi stavo anche chiedendo se avrei dovuto deallocare tutti i dati assegnati all'uscita.

Ho deciso comunque di implementare la deallocazione e ho scoperto che il programma si è bloccato durante la deallocazione. Analizzando il crash, ho trovato un errore nell'implementazione della struttura dati principale e degli algoritmi (una perdita di memoria).

Le lezioni che ho imparato sono state:

  1. Implementa sempre deallocazione per i dati che assegni, questo lo rende più riutilizzabile nel caso in cui desideri incorporare il tuo codice in un sistema più grande.
  2. La deallocazione può servire come ulteriore verifica che i dati allocati si trovino in uno stato coerente al momento del rilascio.

Solo i miei 2 centesimi.

Modifica

Piccola precisazione: ovviamente tutta la memoria allocata ad un processo viene rilasciata quando il processo viene terminato, quindi se l'unico requisito è quello di rilasciare la memoria allocata, farlo esplicitamente è davvero una perdita di tempo.

    
risposta data 21.04.2012 - 14:30
fonte
12

Libera sempre le tue risorse. Liberare tutte le risorse è importante perché è l'unico modo per essere in grado di rilevare efficacemente le perdite. Per il progetto a cui sto lavorando ho persino dei wrapper attorno a malloc / realloc / free per inserire canarini, tenere traccia delle statistiche, ecc .; semplicemente per rilevare i problemi prima.

Tuttavia, ad eccezione del rilevamento delle perdite, per le risorse che vengono liberate all'uscita (non prima) è una perdita di tempo. Il sistema operativo deve essere in grado di liberarlo (ad esempio nel caso in cui il processo si blocchi, o anche solo liberando la RAM utilizzata per il codice del processo); e il sistema operativo dovrebbe essere in grado di liberarlo più velocemente possibile dallo spazio utente perché il kernel farà "all'ingrosso" anziché "frammentario" e ci saranno meno transizioni tra il kernel e il processo coinvolto.

Fortunatamente non devi scegliere in un modo o nell'altro. Se vuoi assicurarti che il tuo codice sia corretto (e lo fai), ma vuoi anche la migliore prestazione possibile, allora fai qualcosa del tipo:

#ifndef FAST_EXIT
    free(stuff);
#endif
    
risposta data 20.03.2012 - 04:11
fonte
8

La routine di pulitura può essere utile se lo si fa periodicamente per recuperare spazio, o per dimostrare che si è in grado di recuperare esattamente quanti nodi sono stati allocati, per verificare che non ci siano perdite di memoria. Ma come servizio di pulizia immediatamente prima che il processo muoia, non ha senso, dal momento che il sistema operativo riprende il controllo di tutta l'arena della memoria in quell'istante.

    
risposta data 19.03.2012 - 15:59
fonte
4

Will there be a different behavior later?

C'è una domanda critica relativa a questa che devi chiedere:

Qualcuno potrà mai più utilizzare questo codice per qualsiasi motivo?

Se la risposta potrebbe mai essere sì, se il codice è usato da solo o come parte di un sistema più grande, hai creato una memoria monumentale che perde la mina terrestre per la prossima persona da calpestare.

È molto difficile ricordare durante i corsi che stai imparando a fare software che altre persone useranno compreso futuro-te (piuttosto che risolvere il problema dei compiti a casa del giorno) . Ciò significa che devi rispettare determinati comportamenti di programmazione di base, tra cui: restituire le risorse quando hai finito con loro.

    
risposta data 20.03.2012 - 14:23
fonte
2

Se implementi il tuo tipo di dati "elenco collegato" non scrivendo una routine di pulizia / decostruttore ti daranno più mal di testa a lungo termine di quanto potresti pensare.

Senza il codice di pulizia riutilizzare ciò che hai scritto sarà molto più difficile dal momento che il tuo tipo non può essere utilizzato senza prestare particolare attenzione (ad esempio, non crearli mai in una funzione o ciclo, ma preferibilmente esclusivamente in main ).

Fai un favore a te stesso e agli altri e scrivici solo list_cleanup o ~List .

    
risposta data 20.03.2012 - 10:59
fonte
1

Su sistemi multiutente, il sistema operativo libererà sempre tali risorse perché sarebbe un rischio per la sicurezza se non lo fosse. Il contenuto della tua memoria potrebbe finire nel processo di qualcun altro!

    
risposta data 19.03.2012 - 15:58
fonte
1

Le routine di pulizia possono avere bug proprio come qualsiasi altro codice. Una triste vista è un programma che fa ciò che vuoi tranne che si blocca o si blocca all'uscita. La pratica generale è di avere il codice pulito dopo di sé, ma la pulizia della memoria all'uscita del processo è un caso in cui non è necessario.

    
risposta data 19.03.2012 - 17:48
fonte
1

Quasi sempre si. Semafori di memoria condivisa gratuiti e risorse del server UDP (il sistema operativo non sa come comunicare ai server UDP connessi che hai finito).

    
risposta data 19.03.2012 - 19:19
fonte
1

Io pulisco sempre le risorse all'uscita normale. È un controllo di sicurezza che le mie allocazioni di risorse / chiamate di deallocazione siano eseguite correttamente. Questo controllo mi ha segnalato bug nascosti in più di un'occasione. È come bilanciare i libri di un'azienda alla fine della giornata.

Potrebbero esserci casi marginali come @MSalter descritti nel suo commento, ma anche questo in genere mi indurrebbe a considerare la gestione della memoria personalizzata, piuttosto che lasciare che il SO pulisca e sperare per il meglio.

    
risposta data 19.03.2012 - 19:57
fonte
0

Se sei sicuro al 100% che nessun altro processo faccia riferimento all'elenco collegato e ai nodi in esso contenuti, OK.

Il 100% è un numero piuttosto alto, però. La tua lista faceva riferimento a un codice di persistenza che è stato raggruppato? Un componente UI ha ancora un handle su di esso? Qualche altro?

Le perdite di memoria generalmente non si verificano di proposito.

    
risposta data 19.03.2012 - 16:44
fonte
0

Il problema è che oggi è un nodo della lista collegata e, domani, è una risorsa che il sistema operativo non può ripulire da solo. È veloce e sicuro lasciare il sistema operativo per ripulire la memoria heap? Sì. Ma è una buona idea? Non necessariamente.

    
risposta data 19.03.2012 - 20:04
fonte
-1

Alcune librerie della GUI C ++ perdono risorse come questa. Questo non è un giudizio di valore, ma la perdita di risorse e il fatto che il sistema operativo li rechi è un evento piuttosto comune in "codice reale".

È sempre buona pratica pulire, non si sa mai quando si vorrà integrare lo strumento con qualcos'altro, e quindi il lavoro è già stato fatto (invece di entrare nel wayback / ricordare la macchina e ricordare tutti i punti hai intenzionalmente perso).

In un caso abbiamo trovato un bug perché la deallocazione stava causando un arresto anomalo perché alcuni altri bug di memoria avevano sovrascritto l'intestazione che elimina. Quindi, a volte può effettivamente aiutarti a trovare bug in altre aree per liberare tutte le tue risorse (puoi trovare un sovraccarico nel blocco precedente).

    
risposta data 23.03.2012 - 02:28
fonte
-2

Gestire la memoria è la best practice mentre prendere la decisione di rilasciarlo in un contesto è l'ottimizzazione!

Ora la palla è nella nostra corte!

    
risposta data 23.03.2012 - 05:44
fonte
-2

Una cosa a cui pensare:

Se il tuo codice è in una DLL, allora dovresti pulire in modo sicuro altrimenti, se si presume che l'uscita del processo libererà le risorse, allora la tua DLL non sarà ricaricabile.

    
risposta data 04.04.2012 - 15:41
fonte

Leggi altre domande sui tag