Gestione della memoria completamente automatizzata deterministica e controllabile

2

La gestione della memoria completamente automatizzata aumenta notevolmente la produttività e l'integrità, ma la normale implementazione (GC) ha un problema critico. È non deterministico e non controllabile. Ciò causa molti problemi, come il carico della CPU, che è fondamentale per le applicazioni in tempo reale. Alcuni tipi di ottimizzazioni (GC incrementale / concorrente) possono ridurre questi problemi, ma non sono deterministici e non possono eliminare completamente il problema.

Ho pensato che GC non è mai stato in grado di risolvere questo problema, ma recentemente ho appreso e capito che l'operazione GC non ha bisogno di essere completamente nascosta. GC può anche essere deterministico e privo di burst della CPU esponendo alcuni controlli di comportamento correttamente progettati.

Penso che (RC + il rilevamento del ciclo invocato manualmente) possa farlo. Ma questo non sembra efficiente. Esiste un approccio migliore per un'implementazione della gestione della memoria completamente automatica, deterministica e controllabile? Oppure posso ottenere qualche link per implementazioni di esempio?

Modifica

Ho aggiunto queste righe per rendere più chiara la mia domanda.

  • deterministico e controllabile in questo contesto significa che l'utente può tracciare ed eseguire il codice alla creazione dell'oggetto e distruggere esplicitamente. E controlla anche la quantità e il tempo di caricamento dell'operazione di gestione della memoria.

  • completamente automatico significa che assegna e cancella la memoria come GC senza ulteriore preoccupazione.

posta Eonil 21.02.2013 - 16:09
fonte

6 risposte

5

Lasciatemi ripetere la frase.

"C'è un modo per ottenere un sistema di gestione della memoria assolutamente perfetto e con tutte le proprietà desiderabili?"

Non esistono sistemi di questo tipo.

    
risposta data 21.02.2013 - 16:16
fonte
4

Il modello C ++ RAII offre una gestione della memoria deterministica e automatica (dal punto di vista del consumatore della biblioteca). Non è esattamente quello che stai cercando, ma è un inizio. Sebbene sia un design opt-in in cui devi scegliere esplicitamente di usarlo con puntatori intelligenti. Teoricamente, un utente di una biblioteca non può sapere nulla della gestione della memoria e ottenere la stessa pulizia automatica di Java.

Forse una lingua con RAII "forzato" potrebbe avvicinarsi a quello che stai cercando.

Il determinismo di RAII è bello perché consente di applicare la stessa tecnica per risorse ancora più preziose della memoria. Come connessioni e maniglie.

void foobar()
{
    //connections are even more precious than memory. A leak is bad news.
    Connection conn("foobar");
    conn.Open();
}//conn is automatically closed as it leaves scope. Memory is free too.
    
risposta data 21.02.2013 - 18:06
fonte
0

C'era una descrizione di Butler Lampson in Hints for Computer System Design ( Revisione dei sistemi operativi 15 , 5, Oct. 1983, p 33-48) di un sistema che combinava sia un collettore incrementale basato sul conteggio automatico dei riferimenti sia un raccoglitore di traccia e spazza che poteva pulire riferimenti circolari irraggiungibili. L'idea è che un'applicazione possa fare affidamento sulla raccolta incrementale per fare la maggior parte del lavoro, quindi fare la "raccolta dei rifiuti" del mondo "utilizzata durante le pause caffè per recuperare strutture circolari accumulate."

Questo era, secondo quel documento, implementato negli ambienti di programmazione di Interlisp-D e Cedar. Cita i seguenti due articoli che non ho ancora letto ma che - afferma Lampson - descrivono il collezionista in modo più dettagliato:

  • Burton, R.R. et al. Panoramica Interlisp-D. In documenti su Interlisp-D, rapporto tecnico SSL-80-4, Xerox Palo Alto Research Center, 1981.
  • Deutsch, L.P. e Bobrow, D.G. Un efficiente garbage collector incrementale automatico. Comm. ACM 19, 9, settembre 1976, pagg. 522-526.
risposta data 21.02.2013 - 18:39
fonte
0

Il Metronome di Garbage Collector di IBM per la JVM è deterministico. Fondamentalmente, funziona continuamente in parallelo con l'applicazione. Si specifica quanto tempo di CPU può utilizzare, con valori di tempo di CPU inferiori che richiedono un heap più grande. Non è adatto per le applicazioni che fanno un sacco di heap thrashing, ma per applicazioni tipiche dovrebbe funzionare bene.

Il depuratore C4 di Azul System per il loro Zing JVM sembra essere simile, ma non l'ho ho visto dettagli tecnici su come funziona, quindi non so se è completamente deterministico o no.

    
risposta data 21.02.2013 - 19:18
fonte
0

Tutti i sistemi di gestione della memoria hanno i loro compromessi. Come punti di risposta di DeadMG, non puoi avere tutto.

Ecco una guida rapida ad alcuni dei compromessi che puoi fare e alcune delle cose che puoi avere.

Nota che questo non è necessariamente completo, ma è un punto di partenza per pensare alle strategie di allocazione della memoria / deallocazione.

1) Manuale full bore: il nadir del determinismo.

Upside: Tu decidi quando ogni pezzo di memoria va via. Non verrai mai messo in pausa da un garbage collector!

Downside: hai GOT di fare tutto il conto della memoria usata da solo. Ed è probabile che a un certo punto ti rovini, specialmente se cerchi di gestire i casi in cui hai bisogno di più memoria e vuoi recuperarli da un'altra parte del tuo programma al volo.

Implementato in: C è il poster per questo bambino.

2) Deallocate sull'ultimo drop di riferimento

Upside: generalmente è possibile vedere dove si verificherà la deallocazione e pianificarla in modo appropriato. Poiché i riferimenti vengono automaticamente ripuliti in modo appropriato, non si perderà la memoria accidentalmente. Se hai il supporto per il compilatore, non puoi sbagliare e perdere memoria.

Downside: se dimentichi o non ti accorgi che stai lasciando cadere l'ultimo riferimento a una massiccia struttura dati, puoi fare un grande successo in un momento inappropriato.

Implementato in: Perl 5, se non sbaglio. Inoltre, se lo si utilizza correttamente, è possibile emularlo in C ++, sebbene dal momento che non sia forzato dal compilatore, non è altrettanto sicuro.

3) GC completi

Aggiornamenti: non devi occupartene. Chiedi oggetti, si presentano e si puliscono quando hai finito con loro. Elimina tutte le seccature di contabilità per la memoria - se c'è memoria libera, sei a posto! Effettuando la deallocazione in blocchi più grandi, ciò riduce anche il costo totale delle deallocations. Se fai un sacco di creare / eliminare, questo può effettivamente essere un buon risparmio.

Downside: il garbage collector può finire per bloccare l'heap per lunghi periodi di tempo. Quanto è lunga una funzione dell'implementazione, ma sarà più grande di ogni singola deallocazione. Gli algoritmi GC più complessi si bloccano per meno tempo, ma a costo di una maggiore complessità. In generale non puoi fare un lavoro utile basato sulla distruzione degli oggetti, perché gli oggetti potrebbero essere distrutti in un momento MOLTO più tardi rispetto a quando è stato usato per l'ultima volta (No RAII per te).

Implementato in: Java è la piattaforma GC con cui ho più familiarità. Le versioni precedenti di Java avevano GC meno potenti e imperversavano molto. La moderna Java non fa molto a meno che tu non stia facendo qualcosa di patologico.

    
risposta data 21.02.2013 - 20:24
fonte
0

È possibile scrivere in C / C ++ il proprio gestore di memoria, che soddisfa le esigenze del progetto. Ho visto questo fatto per risolvere il collo di bottiglia della gestione della memoria in un'applicazione server che aveva un numero enorme di thread con ogni thread che creava e distruggeva un gran numero di piccoli oggetti. Le prestazioni di questa app sono state limitate da una sezione critica nel gestore della memoria, ed è stato risolto dai thread che acquisiscono blocchi di memoria molto più grandi e gestiscono i propri oggetti.

È anche possibile creare un'applicazione in C / C ++ che eviti in gran parte l'uso dell'heap per l'allocazione della memoria. L'applicazione crea grandi matrici di oggetti di dimensioni fisse all'avvio, quindi utilizza solo indici per l'array di quel tipo di oggetto. Credo che questa sia stata una strategia in alcuni grandi giochi per computer negli anni '90. Elimina completamente il problema della frammentazione della memoria e, grazie ai thread con la propria cache di numeri di indice che possono utilizzare, riduce l'allocazione della memoria di conflitto.

    
risposta data 21.02.2013 - 21:03
fonte

Leggi altre domande sui tag