Codice gestito: GC si può occupare di durante la compilazione?

5

La raccolta dei dati inutili avviene durante il runtime, in tempo reale, mentre il codice gestito è in esecuzione. In C ++, tuttavia, dobbiamo scrivere istruzioni di distruzione nel codice. Quindi potremmo dire che GC è incorporato nel codice (da noi). Quindi, perché le lingue gestite non possono comportarsi in questo modo? Il compilatore analizzerebbe il codice e inserirà i metodi di destruct nelle posizioni appropriate nel codice oggetto. Se la risposta a questo è che l'eleggibilità per GC per alcuni oggetti diventa chiara solo durante l'esecuzione, potrebbe essere comunque sensato costruire istruzioni di distruzione nel codice compilato in alcuni casi, no? Forse nella maggior parte dei casi?

    
posta stevie 07.01.2017 - 21:41
fonte

5 risposte

8

The compiler would analyse the code and insert the destruct methods into the appropriate places in the object code.

La risposta a questo è la stessa della risposta al secondo paragrafo di questa domanda, che rende una dichiarazione molto simile: C ++ delete vs Java GC .

Capire la durata degli oggetti equivale a risolvere il problema di interruzione, quindi, no, il compilatore può non inserire i metodi di destruct nelle posizioni appropriate nel codice oggetto. Questo è particolarmente vero per le lingue con chiusure.

Ma aspetta, il C ++ ha chiusure e niente GC, come funziona? Beh, non è così: puoi mandare in crash il tuo programma (o più precisamente: eseguire un comportamento indefinito) usando le chiusure, esattamente perché il compilatore non riesce a capire le durate delle tue variabili chiuse. L'aliasing è un'altra cosa che rende davvero difficile l'analisi della memoria.

In generale, a meno che la tua lingua sia specificamente progettata (e specificamente limitata ) per tale analisi, è impossibile.

Alcune JVM eseguono Escape Analysis in fase di compilazione per capire se un riferimento uscirà dall'ambito locale o meno, e se non lo fa, l'oggetto può essere allocato nello stack invece di il mucchio. Ma, avete indovinato, EA equivale a risolvere il problema di interruzione.

Azul JVM esegue Escape Detection : alloca gli oggetti nello stack e quando vede un riferimento che sfugge all'ambito locale, si rialloca sull'heap e ricollega tutti i riferimenti esistenti. Questo accade in fase di esecuzione, e quindi non è soggetto al problema di interruzione ... ma stavi parlando di farlo in fase di compilazione, quindi questo non conta.

    
risposta data 08.01.2017 - 02:57
fonte
4

In C++ however, we need to write destruct statements into the code.

Questo non è corretto. In C ++, la creazione di oggetti legati all'ambito rilascia il programmatore da tale carico. I casi in cui è necessario utilizzare esplicitamente le istruzioni "new" e "delete" sono per lo più i casi in cui la durata dell'oggetto può essere determinata solo in fase di esecuzione (quindi non può essere definita dal compilatore in cui è necessaria la corretta istruzione "delete" essere posto o quando deve essere chiamato).

So why can't managed languages behave like this?

Quindi, mettendo da parte la supposizione sbagliata e interpretando questa parte della domanda come "perché i linguaggi gestiti non possono fornire anche una gestione della memoria legata all'ambito come C ++" - allora la risposta è, possono: C ++ / CLI fornisce tali un meccanismo, anche per oggetti "gestiti". E se la gestione dell'ambito non si adatta, la situazione diventa uguale a quella sopra - nella maggior parte dei casi, le informazioni quando l'oggetto deve essere distrutto è semplicemente non disponibile in fase di compilazione .

Bene, ho cambiato la mia affermazione di cui sopra da "sempre" a "principalmente", dal momento che dopo aver ripensato alla tua domanda, suppongo tu abbia avuto qualcosa del genere in mente:

  • un oggetto viene assegnato da "nuovo" da qualche parte all'inizio dell'ambito locale
  • l'oggetto viene utilizzato solo all'interno di quell'ambito e in nessun altro posto
  • quando lo scope è lasciato, l'oggetto potrebbe essere immediatamente distrutto e deallocato, senza la necessità di passarlo al GC per liberarlo in seguito

E la tua domanda è "il compilatore può determinare il fatto che l'oggetto non lascia l'ambito locale in alcuni casi e quindi generare una chiamata di distruzione automatica alla fine dell'ambito"? Se questa è la tua domanda, penso che la risposta di @ JörgWMittag sia ciò che stai cercando.

    
risposta data 07.01.2017 - 22:29
fonte
1

Perché le perdite di memoria esistono in primo luogo nelle lingue senza garbage collection?

Perché è difficile per gli sviluppatori trovare esattamente quando deallocare oggetti specifici (o liberare la memoria allocata in precedenza). Anche se prendi una variabile di breve durata che ha una durata di vita facilmente rilevabile:

Declare and assign a value
Use the variable
Destroy the variable

il codice può comportarsi male, ad esempio lanciando un'eccezione sulla seconda riga, che porta alla variabile che non viene distrutta.

È simile per un compilatore immaginario basato su GC. Mentre alcuni pattern possono essere elaborati da un'app per identificare, durante la compilazione, quando una variabile specifica deve essere distrutta, la gestione di qualsiasi caso tranne i casi molto elementari richiederebbe troppo tempo per il controllo statico.

Dato che sembra che tu usi .NET, probabilmente hai provato i Contratti di codice e il compilatore corrispondente. Quanto dura la costruzione? Per un Hello World, pochi secondi. Per una piccola app, diversi minuti. Per app, ore o giorni o settimane in media scala. Non è che la tecnologia stessa sia inutile: è molto interessante e porta i suoi benefici. Ma aspettando ore ogni volta che hai bisogno di ricompilare l'app? Non è una buona idea.

    
risposta data 07.01.2017 - 22:00
fonte
0

Il problema di liberare memoria (o oggetti) è sapere esattamente quando possono essere rilasciati. Un oggetto può essere referenziato da più posti allo stesso tempo. L'oggetto o la sua memoria possono essere rilasciati quando nessuno lo fa più riferimento.

È facile per un compilatore determinare che un particolare riferimento a un oggetto scompare. Tuttavia, un riferimento che va via non significa che l'oggetto può essere rilasciato, perché potrebbe esserci un numero qualsiasi di altri riferimenti all'oggetto. Quindi è abbastanza impossibile determinare in fase di compilazione che un oggetto possa essere rilasciato, almeno per la maggior parte degli oggetti.

    
risposta data 08.01.2017 - 00:05
fonte
-3

Non c'è alcun vantaggio per il tuo approccio. Il GC viene eseguito dal framework in momenti convenienti o quando non può essere posticipato. Suggerisci di farlo nei momenti predeterminati. È probabile che questi siano momenti più sconvenienti.

Per quanto riguarda le prestazioni, l'opzione di runtime di solito è la migliore. Se hai bisogno del controllo per alcuni sistemi embedded in tempo reale o di piccole dimensioni, potresti volere o doverti pulire da solo e utilizzare un linguaggio compilato tradizionale. Ma l'opzione intermedia è inutile, dato ciò che è disponibile oggi.

    
risposta data 07.01.2017 - 22:49
fonte

Leggi altre domande sui tag