Supporto a run time
Transcript
Supporto a run time
05/01/2014 RUN TIME ENVIRONMENT MEMORY ORGANIZATION Compiler must do the storage allocation and provide access to variables and data Memory management Stack allocation Heap management Garbage collection 1 05/01/2014 MEMORY ORGANIZATION hypothesis Run time memory is based on contigued bytes The smaller addressed space is a byte (4 bytes = word) The number of bytes for a date depend on its type The memory structure depend on the target machine The space (in bytes) required for the code is calculated at compile time. Code Static Steak Free memory Heap 3 STATIC VS. DYNAMIC ALLOCATION Static: Compile time, Dynamic: Runtime allocation Many compilers use some combination of following Stack storage: for local variables, parameters and so on Heap storage: Data that may outlive the call to the procedure that created it Stack allocation is a valid allocation for procedures since procedure calls are nested 2 05/01/2014 STATIC VS. DYNAMIC Static Compile time Code based ALLOCATION Dynamic Run time Code + Data based Strategies Stack allocation Heap allocation 5 STORIA DELL’ALLOCAZIONE DELLA MEMORIA Allocazione statica (Static allocation) Una caratteristica del Fortran (fino al Fortran77) Implca che le dimenzioni degli arrays sia conosciuta a compile time no funzioni o sottoprogrammi ricorsivi Nessuna allocazione dinamica di strutture dati Grande Efficienza: l’accesso ai dati è di norma diretto Sicurezza Nessuna possibilita di out of memory a runtime 3 05/01/2014 STORIA DELL’ALLOCAZIONE DELLA MEMORIA Stack Allocation Introdotta con Algol58 Il tempo di vita (lifetime) è collegato con l’attivazione delle procedure Implementato attraverso l’utilizzo dei record di attivazione (stack frame): Differenti invocazioni istanziano differenti versioni delle variabili locali; il valore delle variabili locali non persiste fra successive invocazioni del sottoprogramma La dimenzione delle strutture dati locali può dipendere da un parametro È supportata le ricorsione La dimenzione del valore ritornato da una funzione deve essere nota a compile time Gli oggetti possono essere allocati dinamicamente nello stack ma sono comunque deallocati quando termina la procedure STACK ALLOCATION 4 05/01/2014 SKETCH OF A QUICKSORT PROGRAM ALLOCAZIONE DELLA MEMORIA STACK Alla chiamata di un sottoprogramma una certa quantità di memoria (per variabili locali etc) viene impilata nello stack Quando il sottoprogramma termina tale memoria viene rimossa dallo stack Cio permette di compilare i sottoprogrammi in modo che l’indirizzo relativo delle sue variabili locali sia sempre lo stesso indipendentemente dalla chiamata 10 5 05/01/2014 ACTIVATION FOR QUICKSORT ALBERO DI ATTIVAZIONE Dato che le chiamate di procedura sono annidate nel tempo possiamo utilizzare una rappresentazione di tale chiamate utilizzando un albero detto “albero di attivazione” Le attivazioni sono riportate sull’albero seguendo da sx a dx l’ordine in cui sono state chiamate Un figlio deve terminare prima che possa iniziare l’attiviazione alla sua destra La sequenza delle chiamate corrisponde ad una visita in preordine dell’albero di attivazione La sequenza dei ritorni corrisponde ad una visita in postordine dell’albero delle attivazioni 12 6 05/01/2014 ACTIVATION TREE REPRESENTING CALLS DURING AN EXECUTION OF QUICKSORT ACTIVATION RECORDS Procedure calls and returns are usaully managed by a run-time stack called the control stack. Each live activation has an activation record (sometimes called a frame) The root of activation tree is at the bottom of the stack The current execution path specifies the content of the stack with the last activation has record in the top of the stack. 7 05/01/2014 A GENERAL ACTIVATION RECORD Temporary values Local data A saved machine status An “access link” A control link Space for the return value of the called function The actual parameters used by the calling procedure DOWNWARD-GROWING STACK OF ACTIVATION RECORDS 8 05/01/2014 DESIGNING CALLING SEQUENCES Values communicated between caller and callee are generally placed at the beginning of callee’s activation record Fixed-length items: are generally placed at the middle Items whose size may not be known early enough: are placed at the end of activation record We must locate the top-of-stack pointer judiciously: a common approach is to have it point to the end of fixed length fields. DESIGNING CALLING SEQUENCES The caller evaluates the actual parameters The caller stores a return address and the old value of top-sp into the callee's activation record. The callee saves the register values and other status information. The callee initializes its local data and begins execution. Parameter and return value Control link Stauts Temporaries an local data Parameter and return value chiamante Control link Stato salvato Dati temporanei e locali 18 chiamato 9 05/01/2014 DIMENSION VARIABLE Two pointers are required top_sp e top top_sp Parametri attuali e valore di ritorrno Control link Stato salvato Puntatore ad a Puntatore ad b Array a top Array b Parametri attuali e valore di ritorrno Control link Stato salvato Dati temporanei e locali 19 CORRESPONDING RETURN SEQUENCE The callee places the return value next to the parameters Using information in the machine-status field, the callee restores top-sp and other registers, and then branches to the return address that the caller placed in the status field. Although top-sp has been decremented, the caller knows where the return value is, relative to the current value of top-sp; the caller therefore may use that value. 10 05/01/2014 ACCESS TO DYNAMICALLY ALLOCATED ARRAYS SEQUENZA DI RITORNO Il chiamato Posiziona il valore di ritorno subito dopo i parametri Ripristina il registro top.sp e gli altri registri quindi passa il controllo all’indirizzo di controllo salvato fra informazioni di stato. Recupera il valore dello stack pointer 22 11 05/01/2014 ACCESSO ALLE VARIABILI NON LOCALI IN ASSENZA DI PROCEDURE ANNIDATE Lo scope in tal caso è costituito dalle variabili locali e dalle variabili globlali Le variabili globali vengono allocate nella parte di memoria riservata ai dati statici Le variabili locali nel record di attivazione del sottoprogramma dove sono definite 23 ACCESSO ALLE VARIABILI NON LOCALI IN PRESENZA DI PROCEDURE ANNIDATE: USO DELL’ACCESS LINK La procedura q con livello di annidamento nq richiama la procedura p con livello di annidamento np np > nq, in tal caso p deve essere definita all’interno di q in tal caso è semplice ad access link di p viene copiato il valore del record di attivazione di q La chiamata è ricorsiva (p=q), in questo caso l’access link della nuova attivazione è identico alla precedente np < nq la procedura q deve essere annidata in r e la definizione di p deve essere immediatamente annidata in r. Il recordi di attivazione più recente di r puo essere localizzato seguento la catena si access link per np – nq + 1 passi. 24 12 05/01/2014 ACCESSO ALLO SCOPE TRAMITE DISPLAY È un array di puntatori di dimensione pari al livello di annidamento Ciascun puntatore punta al record di attivazione più in alto nello stack con quel livello di annidamento 25 ALLOCAZIONE DELLA MEMORIA Heap Allocation Lisp (~1960) Gli oggetti sono allocati e deallocati dinamicamente, in qualsiasi ordine, e il lifetimes degli oggetti non sono correlati con la invocazione delle funzioni Permette strutture dati ricorsive (eg alberi) La dimenzione delle strutture dati può variare dinamicamente Oggetti dimenzionati dinamicamente possono esser ritornati come risultato di una funzione Permette ai linguaggi di programmazione di supportare “first-class functions” (che sono implementate per mezzo di closures) Molti moderni linguaggo forniscono sia stack che heap allocation 26 13 05/01/2014 MEMORY MANAGER Two basic functions: Allocation Deallocation Properties of memory managers: Space efficiency Program efficiency Low overhead TYPICAL MEMORY HIERARCHY CONFIGURATIONS 14 05/01/2014 LOCALITY IN PROGRAMS The conventional wisdom is that programs spend 90% of their time executing 10% of the code: Programs often contain many instructions that are never executed. Only a small fraction of the code that could be invoked is actually executed in a typical run of the program. The typical program spends most of its time executing innermost loops and tight recursive cycles in a program. ALLOCAZIONE ESPLICITA SU HEAP Esempi sono C, C++, Pascal dove il programma alloca e dealloca memoria heap per gli oggetti Garbage = dispersione della mamoria Se non ci sono altri puntatori che puntano al primo alemento della lista quando termina la funzione gli oggetti diventano irragiungibili quindi garbage 30 15 05/01/2014 Allocazione esplicita su Heap Dangling references free( P->next ); 31 Allocazione esplicita su Heap Dangling references which has caused P->next to become a dangling pointer (and a potential delayed effect run-time error) as well as creating some garbage 32 16 05/01/2014 PERCHÈ GARBAGE COLLECT? Quando eseguiamo list = list->next; // cancella il primo elementoelement Il programma dovrebbe deallocare gli oggetti condivisi? (questo è complesso 33 ma corretto) ALLOCAZIONE/DEALLOCAZIONE ESPLICITA. PROBLEMI? Quale funzione è responsabile della deallocazione di un oggetto quando non è più necessario? Gli oggetti condivisi fra diverse strutture dati rendono complesso conoscere quando viene rimossa l’ultimo riferimento Una soluzione comune è aggiungere un “reference counts” agli oggetti (ma questa soluzione ha alcuni problemi) Un alternativa e duplicare (Cloning) gli oggetti in modo da eliminare il problema della condivisione degli oggetti. Questa soluzione non è efficiente. Memory allocation errors are a major source of problems in C/C++ code (random crashes, memory leaks) Esistono numerosi tool per la localizzazione di errori di “memory allocation” (Purify, ObjectCenter, Insure++) 34 17 05/01/2014 GARBAGE COLLECTION 35 THE ESSENCE Programming is easier if the run-time system “garbage-collects” --- makes space belonging to unusable data available for reuse. Java does it; C does not. But stack allocation in C gets some of the advantage. 36 18 05/01/2014 DESIDERATA Speed --- low overhead for garbage collector. Little program interruption. 1. 2. Many collectors shut down the program to hunt for garbage. Locality --- data that is used together is placed together on pages, cache-lines. 3. 37 THE MODEL --- (1) There is a root set of data that is a-priori reachable. Example: In Java, root set = static class variables plus variables on run-time stack. Reachable data : root set plus anything referenced by something reachable. 38 19 05/01/2014 THE MODEL --- (2) Things requiring space are “objects.” Available space is in a heap --- large area managed by the run-time system. Allocator finds space for new objects. Space for an object is a chunk. Garbage collector finds unusable objects, returns their space to the heap, and maybe moves objects around in the heap. 39 GARBAGE COLLECTION Garbage collection (GC) - Il processo di recuperare tali record e renderli disponibili per l'allocazione di nuovi record, non viene eseguito dal compilatore, ma a runtime, dai programmi di supporto collegati al codice compilato (in quanto, ovviamente, i record presenti in memoria dipendono dai dati che sono stati inseriti dall'utente). Per individuare il garbage, l'approccio ideale sarebbe usare la definizione dinamica della liveness. Tuttavia, non essendo questa computabile, ci dobbiamo basare sull'approssimazione conservativa della raggiungibilità del record. Il compilatore dovrà garantire che ogni variabile viva è raggiungibile e, al tempo stesso, minimizzare il numero di variabili raggiungibili che non sono vive. 40 20 05/01/2014 ESEMPIO DI GARBAGE class node { int value; node next; } node p, q; p = new node(); q = new node(); q = p; delete p; 41 IL GARBAGE COLLECTOR “PERFETTO” Nessun impatto visibile sull’esecuzione del programma Opera con qualsiasi programma e sulle sue strutture dati: Recupera tutte le celle garbage (e solo quelle garbage) rapidamente Incrementale, può soddisfare requisiti real-time Ha un eccellente gestione della localita spaziale dei riferimenti Ad esempio gestisce le strutture dati ciclliche No eccessivo paging, nessun effetto negativo sulla cache Gestisce l’heap efficentemente Soddisfa sempre le richieste di allocazione e non provoca frammentazione della memoria heap. 42 21 05/01/2014 COSTO DEL GC I primi sistemi Lisp furono noti per i lunghi stop nel mezzo di sessioni interattive a causa dell’esecuzione del gc. Algoritmi migliori e processori più veloci hanno reso il gc un problema molto minore. GC è ancora da evitare per molte applicazioni real-time (dove il tempo di risposta richiesto e inferiore ai millisecondi), Per la maggior parte delle applicazioni. Il problema è: “Which is more important:software which is free of memory leaks and memory allocation errors, ... or software which is a little faster but less reliable and takes twice as long1 to debug?” 43 A HEAP Free List 44 ... Object 1 Object 2 Object 3 22 05/01/2014 TAXONOMY ReferenceCounters 45 Garbage Collectors TraceBased REFERENCE COUNTING The simplest (but imperfect) method is to give each object a reference count = number of references to this object. OK if objects have no internal references. Initially, object has one reference. If reference count becomes 0, object is garbage and its space becomes available. 46 23 05/01/2014 REFERENCE COUNTING Una tecnica semplice utilizzata in molti sistemi, eg, Unix usa tenere traccia di quando un file può essere cancellato C++ “smart pointer” (e.g., auto_ptr) usa il e reference counter Il costo del gc è distribuito sull’intero programma esecuzione Richiede spazio e tempo per memoriazzare e incrementare (decrementare) il conatore ogni qualvolta un riferimento ad una cella e aggiunto (eliminato) 47 EXAMPLES Integer i = new Integer(10); Integer object is created with RC = 1. j = k; (j, k are Integer references.) Object referenced by j has RC--. Object referenced by k has RC++. 48 24 05/01/2014 TRANSITIVE EFFECTS If an object reaches RC=0 and is collected, the references within that object disappear. Follow these references and decrement RC in the objects reached. That may result in more objects with RC=0, leading to recursive collection. 49 REFERENCE COUNTING Assieme ad ogni record p, viene memorizzato un numero (reference count) che indica quanti puntatori x.fi a quel record sono presenti. Il compilatore emette istruzioni per far sì che ogni volta che un nuovo x.fi punta a p, il reference count di p viene incrementato, mentre viene decrementato quello di r a cui puntava in precedenza. Se decrementando il reference count di r questo assume il valore zero, r viene inserito nella freelist. Se esistono dei record a cui r puntava, il loro refcount deve essere a sua volta diminuito di uno. Ciò viene fatto non subito, ma al momento (successivo) in cui r verrà rimosso dalla freelist, per i seguenti motivi: viene diviso in più parti il decremento ricorsivo, rendendo più uida l'esecuzione del programma 2. si risparmia spazio: il codice per il decremento ricorsivo è unico (nell'allocatore). Il codice per vericare se refcount ha raggiunto zero, tuttavia, deve comunque essere ripetuto per ogni decremento. 1. 50 25 05/01/2014 PSEUDO-CODICE PER REFERENCE COUNTING // chiamata da New function allocate(): newcell = freeList; freeList = freeList.next; return newcell; // chiamatta dal programma per creare // una nuova istanza di un oggetto function New(): if freeList == null then report an error; newcell = allocate(); newcell.rc = 1; return newcell; // chiamata da Update procedure delete(T): T.rc -= 1; if T.rc == 0 then foreach pointer U held inside object T do delete(*U); free(T); // chiamata dal programma per // overwrite una variabile // puntatore R with con un // altro valore S procedure Update(var R, S): if S != null then S.rc += 1; delete(*R); *R = S; // chiamata da delete procedure free(N): N.next = freeList; freeList = N; 51 rc è il campo reference count dell’oggetto REFERENCE COUNTING: EXAMPLE Heap space root set 1 2 1 1 1 2 1 1 52 26 05/01/2014 BENEFICI DEL REFERENCE COUNTING overhead incrementale GC overhead è distribuito lungo tutta la computazione ==> tempo di risposta omogeneo nelle situazioni interattive. (Contrasto con “stop and collect approach”.) Applicazioni real-time Riuso immediato delle celle libere se RC == 0, la cella è aggiunta alla put free list 53 BENEFICI DEL REFERENCE COUNTING Semplicità dell’implementazione Può coesistere con la gestione manuale della memoria heap Buona gestione della località spaziale il programma accede alle locazioni di memoria che probabilmente sono sul punto di di essere utilizzare. (In contrasto con una “marking phase” durante la quale viene scorsa tutta la memoria) la maggioranza degli oggetti hanno una vita breve; il reference counting recupererà e riutilizzera tali oggetti rapidamente. (In contrasto con con uno schema dove gli oggetti morti rimangono inutilizzati per un lungo periodo vino a quando il prossimo gc a rilevato un “out of memory”.) 54 27 05/01/2014 REFERENCE COUNTING: PROBLEMI Space overhead Time overhead 1 word per il contatore Ogni volta che un puntatore è aggiornato: aggiornare due reference counters (decrementare il vecchio target, incrementare il sorgente). L’accesso in memoria è costoso. Il codice è fragile (se prodotto by hand) È molto facile dimenticare di incrementare o decrementare un reference counter (eg quando si passa un oggetto ad un sottoprogramma) Dimenticare un incremento ==> strange bugs, Dimenticare un decremento ==> memory leaks. 55 REFERENCE COUNTING: CYCLES Heap space Memory leak root set 1 1 1 1 1 2 1 1 56 28 05/01/2014 PROBLEMI Non si può rimuovere memoria garbage con riferimenti ciclici: se due record non sono raggiungibili, ma puntano l'uno all'altro vicendevolmente, il loro reference count rimarrà a uno e non potranno essere rimossi. Soluzioni Richiedere esplicitamente che il programmatore elimini tutti i cicli quando ha finito di usare una struttura Combinare Reference Count con qualche Mark&Sweep, per rimuovere i cicli La gestione dei reference count è computazionalmente pesante! Ogni operazione di aggiornamento di un puntatore implica l'incremento di un reference count, il decremento di quello della variabile puntata precedentemente e le operazioni per la verica del raggiungimento di refcount=0. È possibile attuare qualche ottimizzazione tramite analisi dataflow, ma il peso è comunque elevato. 57 REFERENCE COUNTING Strutture dati cicliche La soluzione ovvia e combinare reference counting con gli altri schemi di gc Eseguire gli altri schemi di gc quando La memoria e esaurita Ad intervalli regolari Per esempio si possono utilizzare campi di 8 bit per il counter. Quando il counter supera il valore massimo, 255, rimane bloccato Quando viene eseguito il gc, recupera gli oggetti cil cui contatore dovrebbe essere zero e resetta i contatori degli altri oggetti. Questo permette di utilizzare meno memoria per i reference counts 58 29 05/01/2014 TAXONOMY Garbage Collectors 59 ReferenceCounters TraceBased Stop-the-World Mark-andSweep Short-Pause Mark-andCompact Basic MODELLO ASTRATTO Gli algoritmi basati sulla traccia calcolano l’insieme degli oggetti raggiungibili e poi prendono il complemento di tali oggetti Processo di riciclo della memoria Il programma mutatore viene eseguito ed effettua richesta di allocazione Il GC determina la raggiungibilità degli oggetti mediante algoritmi basati su traccia Il GC rilascia la memoria degli oggetti non raggiungibili 60 30 05/01/2014 FOUR STATES 1. 2. 3. 4. OF MEMORY CHUNKS Free = not holding an object; available for allocation. Unreached = Holds an object, but has not yet been reached from the root set. Unscanned = Reached from the root set, but its references not yet followed. Scanned = Reached and references followed. 61 MARKING 1. 2. 3. Assume all objects in Unreached state. Start with the root set. Put them in state Unscanned. while Unscanned objects remain do examine one of these objects; make its state be Scanned; add all referenced objects to Unscanned if they have not been there; end; 62 31 05/01/2014 SWEEPING Place all objects still in the Unreached state into the Free state. Place all objects in Scanned state into the Unreached state. To prepare for the next mark-and-sweep. 63 MARK-SWEEP GARBAGE COLLECTION Ogni cella ha un “bit di mark” Le locazioni di memoria “garbage” rimane non raggiungibile e inutilizzata fino a quando l’heap non è piena: quando agisce il GC il programma in esecuzione viene sospeso Fase di Marking Partendo dai roots, aggiorna il mark bit di tutte le celle live Fase di Sweep Inserisce tutte le celle non marcate nella free list Reset il mark bit di tutte le celle marcate 64 32 05/01/2014 MARK-SWEEP (AKA MARK-SCAN) ALGORITHM Il primo utilizzo sembra essere in Lisp La memorizzazione per i nuovi oggetti è ottenuto da un free-pool Nessuna azione extra è eseguita quando il programma copia o sovrascrive i puntatori Quando il pool di libero è esaurito, il New () invoca il mark-sweep gc per reinserire la memoria occupata da oggetti inaccessibili al free-pool e quindi ricomincia MARK-SWEEP EXAMPLE (1) Heap space 66 root set 33 05/01/2014 MARK-SWEEP EXAMPLE (2) Heap space 67 root set MARK-SWEEP EXAMPLE (3) Heap space 68 root set 34 05/01/2014 MARK-SWEEP EXAMPLE (4) Heap space Free unmarked cells 69 root set Viene resettato Il mark bit Delle celle marcate ALGORITMO DI MARK_SWEEP Fase di marcatura Poni il reached bit a 1 e aggiungi alla lista Unscanned ogni oggetto avente un riferimento nel root-set while (Unscanned != 0){ rimuovi un oggetto o da Unscanned for (ogni oggetto o’ avente un riferimento in o){ if (il reached-bit di o’ ==0) { poni il reached-bit di o’ ad 1; aggiungi o’ alla lista Unscanned } } } 70 35 05/01/2014 ALGORITMO DI MARK_SWEEP Fase di pulizia Free = 0; For (ogni blocco di memoria o nell’heap){ if (il reached-bit di o ==0) aggiungi o alla lista Free else poni il reached-bit di o ad 0; } La lista Free contiene oggetti disponibili La lista Unscanned contiene oggetti che sappiamo essere raggiungibili che non sono stati analizzati per verificare se fanno riferimento ad altri oggetti 71 COSTO Il tempo di esecuzione dell'algoritmo DFS è proporzionale al numero R di nodi segnati (cioè dei record raggiungibili) ed è proporzionale alla dimensione dello heap H. L'esecuzione di una garbage collection è quindi c1R + c2H. Il costo per unità di spazio libero sullo heap, o costo ammortizzato di raccolta, è dato dal costo di esecuzione diviso per il numero H − R di parole di memoria libere, cioè (c1R+c2H)/(H−R) . Se la memoria è quasi piena (R~ H) il costo è molto elevato. Se la memoria è quasi vuota (H >> R), il costo è molto ridotto. Se al termine del processo di collection R/H è maggiore di 0.5 (o un'altro valore, secondo qualche criterio) il collector dovrebbe chiedere al sistema operativo di fornire maggiore spazio per lo heap del programma. 72 36 05/01/2014 TAXONOMY Garbage Collectors 73 ReferenceCounters TraceBased Stop-the-World Mark-andSweep Basic Short-Pause Mark-andCompact Baker’s BAKER’S ALGORITHM --- (1) Problem: The basic algorithm takes time proportional to the heap size. Because you must visit all objects to see if they are Unreached. Baker’s algorithm keeps a list of all allocated chucks of memory, as well as the Free list. 74 37 05/01/2014 BAKER’S ALGORITHM --- (2) Key change: In the sweep, look only at the list of allocated chunks. Those that are not marked as Scanned are garbage and are moved to the Free list. Those in the Scanned state are put in the Unreached state. For the next collection. 75 STATI Free: zona di memoria disponibile per essere allocata Unreached: blocchi non raggiungibili, tutti i blocchi inizialmente sono considerati non raggiungibili e vengono riposti nello stato unreached dopo il completamento del gc I blocchi raggiungibili possono essere Scanned UnScanned 76 38 05/01/2014 ALGORITMO DI BAKER Fase di marcatura Scanned = 0 UnScanned = insieme degli oggetti raggiungibile dall’insieme radice while (Unscanned != 0){ sposta un oggetto o da Unscanned a Scanned for (ogni oggetto o’ avente un riferimento in o){ if (o’ appartiend a lista UnReached) sposta o’ da UnReached a Unscanned } 77 ALGORITMO DI MARK_SWEEP Fase di pulizia Free = Free UnReached; UnReached = UnScanned 78 39 05/01/2014 OTTIMIZZAZIONI: STACK ESPLICITO Se si usa un algoritmo DFS standard (ricorsivo), si potrebbe arrivare ad avere H ricorsioni, e quindi H frame sulla pila dei record di attivazione, ossia il garbage collector occuperebbe più memoria dello HEAP stesso. Ciò è decisamente da evitare, perciò si preferisce utilizzare un algoritmo iterativo in cui si gestisce esplicitamente una struttura a pila su cui salvare i record marcati. In tal modo, si otterrà ugualmente una pila di H elementi, ma saranno singole word invece che record di attivazione. 79 OTTIMIZZAZIONI: INVERSIONE DEI PUNTATORI (POINTER REVERSAL) Per ridurre ulteriormente lo spazio occupato, si può osservare che, dopo che il contenuto di un campo x.fi di un record x è stato salvato sullo stack, è possibile riutilizzare lo spazio x.fi. In particolare, è possibile utilizzarlo per salvare il puntatore al record a partire dal quale x era stato raggiunto. Secondo questo ragionamento, è quindi possibile utilizzare lo stesso grafo dei puntatori per salvare anche lo stack, facendo sì che, mentre si stanno esaminando i campi di un record (e i campi dei record a cui questi, a loro volta, puntano), ogni record che si sta esaminando punti al proprio predecessore (cioè al record da cui è puntato) invece che al proprio successore (il record a cui punta normalmente). Ogni volta che tutti i campi di un record sono stati esaminati, i suoi puntatori vengono ripristinati, ricostruendo il grafo originale. 80 40 05/01/2014 function DFS(x) if (x è un puntatore e il record a cui punta non è marcato) imposta root come predecessore (t) marca x while true if (c'è ancora un campo x.fi (contenente il valore y) da esaminare nel record x) if (y è un puntatore e il record puntato da y non è marcato) x.fi t //fai puntare il campo al suo predecessore (pointer reversal) t x //x è il predecessore del record che stiamo esaminando x y //il record corrente è quello puntato da y marca il record corrente x else dall'inversione reversal) y x //salva in y l'indirizzo del record che stavamo esaminando x t //torna ad esaminare il predecessore if (x=root) tutto il grafo è stato visitato. Fine. t x.fi //il nuovo predecessore è quello il cui valore era stato salvato x.fi y //ripristino del puntatore originale (fine del pointer 81 OTTIMIZZAZIONE: ARRAY 1. DI FREELIST Per ridurre la frammentazione della memoria libera si può utilizzare, invece di un'unica freelist, un array di freelist, ognuna delle quali corrisponde ad una certa dimensione dei record ivi contenuti. In tal modo, sarà possibile utilizzare il blocco di memoria più piccolo di dimensioni sufficienti a contenere la variabile da allocare. Se non ci sono blocchi suffientemente piccoli, è possibile usare il più piccolo disponibile e sprecare una parte dello spazio (se si vuole mantenere la dimensione dei blocchi), oppure suddividerlo e reimmettere nell'opportuna freelist la parte di spazio non utilizzata. La creazione delle diverse freelist è demandata alla fase sweep dell'algoritmo. L'uso di array di freelist rende anche più veloce anche l'allocazione di nuove variabili nello heap, perchè l'allocatore non dovrà cercare sequenzialmente in tutta la freelist un blocco di dimensioni sucienti, ma potrà direttamente andarlo a richiedere alle freelist di dimensioni opportune. Frammentazione esterna: sono presenti tanti piccoli record liberi di dimensione insufficiente per l'allocazione che si vuole eseguire. Frammentazione interna: non è possibile trovare spazio libero a sucienza perchè questo è presente, inutilizzato, all'interno di record troppo grandi già allocati. 82 41 05/01/2014 MARK-SWEEP COSTS AND BENEFITS Vantaggi Gestisce le strutture cicliche Nessun space overhead 1 bit utilizzato per marcarre le celle Svantaggi L’esecuzione del programma viene sospesa Può influenza la gestione della memoria virtuale Può causare un paging eccessivo se la dimenzione del working-set size è piccola e l’heap non è tutta nella memoria fisica L’heap può essere frammentata 83 TAXONOMY Garbage Collectors 84 ReferenceCounters TraceBased Stop-the-World Mark-andSweep Basic Short-Pause Mark-andCompact Baker’s Basic 42 05/01/2014 ISSUE: WHY COMPACT? Compact = move reachable objects to contiguous memory. Locality --- fewer pages or cache-lines needed to hold the active data. Fragmentation --- available space must be managed so there is space to store large objects. 85 MARK-AND-COMPACT Mark reachable objects as before. Maintain a table (hash?) from reached chunks to new locations for the objects in those chunks. 1. 2. Scan chunks from low end of heap. Maintain pointer free that counts how much space is used by reached objects so far. 86 43 05/01/2014 MARK-AND-COMPACT --- (2) Move all reached objects to their new locations, and also retarget all references in those objects to the new locations. 3. 4. Use the table of new locations. Retarget root references. 87 EXAMPLE: MARK-AND-COMPACT 88 free 44 05/01/2014 EXAMPLE: MARK-AND-COMPACT 89 free EXAMPLE: MARK-AND-COMPACT 90 free 45 05/01/2014 EXAMPLE: MARK-AND-COMPACT 91 free EXAMPLE: MARK-AND-COMPACT 92 free 46 05/01/2014 EXAMPLE: MARK-AND-COMPACT 93 free EXAMPLE: MARK-AND-COMPACT 94 free 47 05/01/2014 EXAMPLE: MARK-AND-COMPACT 95 free EXAMPLE: MARK-AND-COMPACT 96 free 48 05/01/2014 MARK AND COMPACT Una volta effettuata la marcatura invece di procedere alla rimozione è conveniente ricopiare tutti gli oggetti raggiungibili verso uno dei due estremi dell’heap 97 ALGORITMO DI MARK_COMPACT Fase di marcatura UnScanned insieme degli oggetti raggiungibili dall’insieme radice while (Unscanned != 0){ rimuovi un oggetto o da Unscanned for (ogni oggetto o’ avente un riferimento in o){ if (o’ non è stato ragiunto) { marca o’ come ragiunto aggiungi o’ alla lista Unscanned } } } 98 49 05/01/2014 ALGORITMO DI MARK_COMPACT Calcolo delle nuove locazioni For (ogni blocco di memoria o nell’heap a partire dal basso){ if (o è ragiunto) { for (ofni riferimento o.r in o new Location(0) = free; free = free + sizeof(o) } 99 ALGORITMO DI MARK_COMPACT Fase di aggiornamento dei riferimenti For (ogni blocco di memoria o nell’heap a partire dal basso){ if (o è ragiuunto) { for (ogni ogni riferimento 0.r in o) o.r = new Location(o,r) = free; } } for (ogni riferimento r nell’insieme radice) r = new Location (r); 100 50 05/01/2014 TAXONOMY Garbage Collectors 101 ReferenceCounters TraceBased Stop-the-World Mark-andSweep Basic Short-Pause Mark-andCompact Baker’s Basic Cheney’s A different Cheney, BTW, so no jokes, please. CHENEY’S COPYING COLLECTOR A shotgun approach to GC. 2 heaps: Allocate space in one, copy to second when first is full, then swap roles. Maintain table of new locations. As soon as an object is reached, give it the next free chunk in the second heap. As you scan objects, adjust their references to point to second heap. 102 51 05/01/2014 COPYING COLLECTOR Lo heap viene diviso in due parti: from-space (dove si trovano idati) to-space (parte vuota) . Attraversando il grafo dei record raggiungibili, si copiano man mano tali record nel to-space, occupando senza frammentazione i primi blocchi di memoria attigui. La copia nel to-space si dice quindi compatta. I nodi radice (le variabili dello stack) vengono quindi fatti puntare ai dati del to-space, rendendo il from-space non più raggiungibile. Alla successiva esecuzione dell'algoritmo, il from-space e il to-space saranno invertiti. 103 COPYING A LINKED LIST [Cheney’s algorithm] pointer root A 104 from-space forwarding address B C D to-space A’ B’ C’ D’ Cells in to-space are packed 52 05/01/2014 FLIPPING SPACES pointer 105 to-space forwarding address from-space root A’ B’ C’ D’ COPYING COLLECTOR Nel from space sono presenti due puntatori: next indica il punto in cui inizia la parte di memoria libera (e quindi dove, su richiesta, verranno allocate le prossime aree di memoria), limit indica il termine dello spazio disponibile. Quando next raggiunge limit, viene eseguita la collection. Durante il normale funzionamento del sistema, next può solo crescere: viene ridotto unicamente dall'esecuzione della collection. Quando si comincia l'esecuzione di una collection, next punta alla base del to-space, e viene incrementato di size(p) ogni volta che un record p viene copiato. 106 53 05/01/2014 COPYING COLLECTOR Forwarding È il nome dell'operazione base dell'algoritmo. Si esegue il forwarding di un puntatore p quando, dato un p che punta al from-space, lo si modica per puntare agli stessi dati nel to-space. Funziona in tre sottocasi diversi: 1. Se p punta ad un record del from-space che è già stato copiato, allora p.f1 è il forwarding pointer che indica dove si trova la copia nel to-space. È riconoscibile come tale dall'indirizzo, che è interno al to-space. 2. Se p punta al from-space, il contenuto dell'indirizzo puntato viene copiato nel to-space e p.f1 viene fatto puntare alla nuova locazione del record. 3. Se p non è un puntatore oppure se punta al di fuori dal fromspace, il forwarding non fa nulla. 107 COPYING COLLECTOR TRADEOFFS Vantaggi: basso overhead nell’allocazone Il check dell’Out-of-space richiede un confronto fra indirizzi Consente un efficente allocazione di celle di dimenzioni variabili Vantaggi: compattazione Elimina la frammentazione, buona localita dei riferimenti Scantaggi: dimenzione della memoria heap disponibile 108 54 05/01/2014 ALGORITMO DI CHENEY Esegue la copia tramite una visita breadth-rst. Non necessità di uno stack esterno o dell'inversione dei puntatori perché introduce, una copia di puntatori next e un puntatore scan che indica quali record sono stati scanditi. I record compresi tra scan e next, sono stati copiati nel to-space ma non ancora modicati tramite forwarding (contengono riferimenti al fromspace). I record precedenti a scan, invece, sono già stati modicati dal forwarding (contengono solo riferimenti al to-space). Al termine del processo di collection, scan raggiunge next. 109 CHENEY SCAN Root set A E D C A scan A F B scan B A scan free B C B C free D free Garbage Collection 55 05/01/2014 ALGORITMO DI CHENEY Località dei riferimenti L'uso di un algoritmo breadth rst crea problemi con la località dei riferimenti, in quanto vengono memorizzati in aree adiacenti di memoria i record che hanno la stessa distanza dalle radici. Avrebbe invece più senso memorizzare vicini i record che sono connessi da una catena di puntatori, in quanto è molto più probabile che si dovrà accedere ad essi in sequenza e, per il funzionamento delle politiche di paginazione della memoria, facilmente in questo modo tali record verranno caricati assieme riducendo il numero di page fault e cache miss, migliorando sensibilmente le prestazioni. Una ricerca depth-rst permetterebbe di ottenere maggiore località, ma richiederebbe l'uso dell'inversione dei puntatori, risultando quindi piuttosto lenta. Un buon approccio è quello ibrido, che utilizza breadth-rst ma che, dopo aver copiato un oggetto, verica tramite depthrst se esiste qualche suo nodo glio da copiargli vicino. 111 LookupNewLocation(o){ /*cerca la nuova posizione di un oggetto se è stato spostato altrimenti assegna all’oggetto lo stato unscanned*/ if (NerLocation(o) == null) { NewLocation(o) = free free = free + sizeof(o) copia o in NewLocation(o); } Return NewLocation(o); } 112 56 05/01/2014 CopyingCollector(){ for (ogni oggetto o nel semispazio From) NewLocation(o) = null unscanned = free = indirizzo base semispazio To for (ogni riferimento r nel root set) sostituisci r con LookupNewLocation(r) while (unscanned == free) { o = oggetto alla locazione unscanned for (ogni riferimento o.r in o) o.r= LookupNewLocation(o,r); unscanned = unscanned + sizeof(o) }} 113 CONFRONTO FRA MARK-SWEEP E COPYING COLLECTION Detti M = dimenzione dell’heap R = percentuale di oggetti vivi Tutti gli oggetti vivi devono essere copiati da un Copying Collector, cosi il tempo e proporzionale a R: tcc = aR Copyng collector visita tutti gli oggetti vivi e sweeps tutti gli elementi dell’heap, cosi il suo tmpo ha due componenti : tms = bR +cM Dove a, b, c sono costanti 114 57 05/01/2014 CONFRONTO Spazio recuperato dal gc mcc = M/2 – R mms = M – R Efficienza e = byte recuperati al secondo ecc = 1/2ar – 1/a ems = (1-r)/(br + c) Dove r = R/M 115 CONFRONTO 116 58 05/01/2014 GENERATIONAL GARBAGE COLLECTION Osservazione: la maggior parte delle celle, che muoino, muoiono giovani Scope annidati sono entrato ed uscito più di frequente, gli oggetti temporanei in uno scope ambito nidificato nascono e muoiono ravvicinati nel tempo Espressioni interne in Scheme sono più giovani di espressioni esterne, in tal modo diventano “garbace prima Dividere l'heap in generazioni, e GC le cellule più giovani più frequentemente Non ci sono tutte le celle durante il ciclo di GC Periodicamente raccoglie li "vecchie generazioni” Ammortizzare il costo di generazione in generazione 117 TAXONOMY Garbage Collectors 118 ReferenceCounters TraceBased Stop-the-World Mark-andSweep Basic Mark-andCompact Short-Pause Incremental Partial Baker’s Basic Cheney’s 59 05/01/2014 SHORT-PAUSE GARBAGE-COLLECTION Incremental --- run garbage collection in parallel with mutation (operation of the program). Partial --- stop the mutation, but only briefly, to garbage collect a part of the heap. 1. 2. 119 PROBLEM WITH INCREMENTAL GC OK to mark garbage as reachable. Not OK to GC a reachable object. If a reference r within a Scanned object is mutated to point to an Unreached object, the latter may be garbage-collected anyway. Subtle point: How do you point to an Unreached object? 120 60 05/01/2014 ONE SOLUTION: WRITE BARRIERS Intercept every write of a reference in a scanned object. Place the new object referred to on the Unscanned list. A trick: protect all pages containing Scanned objects. A hardware interrupt will invoke the fixup. 121 ALGORITMI DI GC INCREMENTALI Per ridurre il tempo di interruzione dell'esecuzione di un programma durante il GC, è possibile usare algoritmi incrementali, cioè che non conducono l'intero processo di collection in un unico passaggio, ma lo eseguono un pezzo alla volta inframezzandosi alla normale esecuzione del programma. Collector:l'algoritmo di collection Mutator: il programma in esecuzione (in quanto è in grado di modicare i dati su cui si sta lavorando). Generalmente gli algoritmi incrementali si basano su un processo di segnatura a tre colori per stabilire l'avanzamento dell'algoritmo. I record possono essere: Bianchi oggetti non ancora visitati dall'algoritmo di ricerca depth-rst o breadth-rst. Grigi gli oggetti sono già stati visitati, ma i loro figli no (è come se si trovassero sulla pila, o tra scan e next) Neri sia gli oggetti sia tutti i loro gli sono già stati visitati e marcati (è come se fossero già stati tolti dalla pila, o se fossero prima di scan). 122 61 05/01/2014 INCREMENTAL COLLECTION A partire dalle radici, si visitano tutti gli oggetti, rendendoli prima grigi, visitando i loro figli e infine rendendoli neri. Quando non sono più presenti oggetti grigi, tutto ciò che è rimasto bianco è garbage. Due invarianti sono comuni a tutti gli algoritmi che si basano su questo principio: Gli oggetti neri non possono puntare a oggetti bianchi Ogni oggetto grigio è sulla struttura dati (pila o coda) del collector. Il mutator, durante il suo lavoro, deve fare attenzione a non rompere tali invarianti, introducendo opportune politiche di coloratura: ad esempio, nell'algoritmo di Dijkstra, Lamport e altri, quanto il mutator salva un puntatore bianco a dentro ad unoggetto nero b, deve colorare a di grigio. 123 LAYOUT DEI DATI Il collector deve essere in grado di operare su qualunque tipo di dato, anche complesso. Deve quindi essere in grado di determinare 1. la dimensione occupata dai dati di ogni record, il numero di campi da cui è formato e se questi campi contengono o meno un puntatore 2. La prima word di un oggetto generalmente viene fatta puntare ad un record di descrizione del tipo (o della classe) che contiene l'indicazione della dimensione e la posizione dei campi puntatore. Tale record deve essere stato creato dal compilatore grazie alle informazioni ricavate dall'analisi semantica. Il compilatore deve anche permettere al collector di identicare se qualunque temporary (registro o area di memoria) contiene un puntatore. Ciò viene fatto compilando un'apposita mappa dei puntatori (pointer map) ogni volta che potrebbe essere necessario eseguire una collection, cioè ad ogni operazione alloc. 124 62 05/01/2014 TAXONOMY Garbage Collectors 125 ReferenceCounters TraceBased Stop-the-World Mark-andSweep Basic Mark-andCompact Baker’s Basic Cheney’s Short-Pause Incremental Partial Generational THE OBJECT LIFE-CYCLE “Most objects die young.” But those that survive one GC are likely to survive many. Tailor GC to spend more time on regions of the heap where objects have just been created. Gives a better ratio of reclaimed space per unit time. 126 63 05/01/2014 PARTIAL GARBAGE COLLECTION We collect one part(ition) of the heap. The target set. We maintain for each partition a remembered set of those objects outside the partition (the stable set) that refer to objects in the target set. Write barriers can be used to maintain the remembered set. 127 COLLECTING PARTITION To collect a part of the heap: 1. 2. A Add the remembered set for that partition to the root set. Do a reachability analysis as before. Note the resulting Scanned set may include garbage. 128 64 05/01/2014 EXAMPLE: “REACHABLE” GARBAGE In the remembered set 129 The target partition Not reached from the root set Stable set GENERATIONAL GARBAGE COLLECTION Divide the heap into partitions P0, P1,… Each partition holds older objects than the one before it. Create new objects in P0, until it fills up. Garbage collect P0 only, and move the reachable objects to P1. 130 65 05/01/2014 GENERATIONAL GC --- (2) When P1 fills, garbage collect P0 and P1, and put the reachable objects in P2. In general: When Pi fills, collect P0, P1,…,Pi and put the reachable objects in P(i +1). 131 EXAMPLE WITH IMMEDIATE “AGING” (1) A B D 132 C root set Young E F Old G 66 05/01/2014 EXAMPLE WITH IMMEDIATE “AGING” (2) D 133 C root set Young E A G F Old B GENERATIONS WITH SEMI-SPACES Youngest . . . From-space 134 root set To-space Middle generation(s) Oldest From-space To-space 67 05/01/2014 Riduce sia il tempo sia lo spazio usati dal metodo copying collection. Si basa sull'osservazione che molti oggetti sono destinati a morire presto, ma se un oggetto è sopravvissuto già ad alcune collection, è probabile che sopravviva a lungo. L’ heap è diviso in generazioni: G0 contiene gli oggetti più giovani. Tutti gli oggetti di G1 sono più vecchi di quelli di G0; gli oggetti in G2 sono più vecchi di quelli di G1 e così via. Ogni area dovrebbe essere esponenzialmente più grande della precedente (es: G0 = 0.5MB,G1 = 2MB,G2 = 8MB). Un oggetto che è sopravvissuto a due o tre collection viene promosso a quella successiva. 135 Al momento di eseguire una collection (si può usare sia il metodo mark&sweep sia copying collection) la si esegue prima su G0 e poi, se necessario, sulle generazioni via via successive. Per trovare gli elementi di G0, non basta guardare le variabili nello stack: potrebbero esistere anche riferimenti all'interno di oggetti vecchi che puntano a oggetti più nuovi. Questa condizione (per fortuna rara, perchè richiede l'aggiornamento di un campo di un oggetto vecchio) renderebbe l'analisi del solo G0 più lenta che non l'attraversamento di tutto il grafo a partire dalle radici. Per ovviare al problema facciamo si che il programma compilato ricordi dove ci sono puntatori da oggetti vecchi ad oggetti nuovi, in modo da poterli trovare immediatamente. Esistono diversi metodi per fare ciò. 136 68 05/01/2014 1. 2. 3. 4. Remembered list: viene generata una lista di oggetti di cui un campo è stato aggiornato. Al momento del GC si cercano all'interno della lista gli oggetti che puntino dentro G0 Remembered set La remembered list potrebbe contenere duplicati di uno stesso oggetto al suo interno. Per evitare il problema, si codica all'interno dello stesso oggetto un bit per indicare l'appartenenza o meno al remembered set. Card marking La memoria è divisa in schede di dimensione 2k. Un oggetto può occupare una o più schede, o parte di una scheda. Ogni volta che un indirizzo b viene modicato, la scheda contenente quell'indirizzo viene marcata (tramite un bit in un apposito array) Page marking Simile al precedente, ma invece di introdurre una gestione manuale delle schede, si usa la paginazione della memoria. Quando un indirizzo viene modicato, un dirty bit viene impostato per quella pagina. In ogni caso, all'inizio della garbage collection, il set di oggetti ricordati indica quali oggetti potrebbero contenere puntatori a G0. Questi oggetti assieme alle variabili dello stack fungono da root variables per l'algoritmo di ricerca scelto. 137 TAXONOMY Garbage Collectors 138 ReferenceCounters TraceBased Stop-the-World Mark-andSweep Basic Mark-andCompact Baker’s Basic Cheney’s Short-Pause Incremental Partial Generational Train 69 05/01/2014 THE TRAIN ALGORITHM Problem with generational GC: 1. 2. Occasional total collection (last partition). Long-lived objects move many times. Train algorithm useful for long-lived objects. u Replaces the higher-numbered partitions in generational GC. 139 PARTITIONS = “CARS” Car 11 Car 12 Train 2 Car 21 Car 22 Car n1 Car n2 140 Train 1 Car 13 ... Car 2k . . . Train n 70 05/01/2014 ORGANIZATION OF HEAP There can be any number of trains, and each train can have any number of cars. You need to decide on a policy that gives a reasonable number of each. New objects can be placed in last car of last train, or start a new car or even a new train. 141 GARBAGE-COLLECTION STEPS Collect the first car of the first train. Collect the entire first train if there are no references from the root set or other trains. 1. 2. Important: this is how we find and eliminate large, cyclic garbage structures. 142 71 05/01/2014 REMEMBERED SETS Each car has a remembered set of references from later trains and later cars of the same train. Important: since we only collect first cars and trains, we never need to worry about “forward” references (to later trains or later cars of the same train). 143 COLLECTING FIRST TRAIN THE FIRST CAR OF THE Do a partial collection as before, using every other car/train as the stable set. Move all Reachable objects of the first car somewhere else. Get rid of the car. 144 72 05/01/2014 MOVING REACHABLE OBJECTS If object o has a reference from another train, pick one such train and move o to that train. Same car as reference, if possible, else make new car. If references only from root set or first train, move o to another car of first train, or create new car. 145 PANIC MODE The problem: it is possible that when collecting the first car, nothing is garbage. We then have to create a new car of the first train that is essentially the same as the old first car. 146 73 05/01/2014 PANIC MODE --- (2) If that happens, we go into panic mode, which requires that: 1. 2. If a reference to any object in the first train is rewritten, we make the new reference a “dummy” member of the root set. During GC, if we encounter a reference from the “root set,” we move the referenced object to another train. 147 PANIC MODE --- (3) Subtle point: If references to the first train never mutate, eventually all reachable objects will be sucked out of the first train, leaving cyclic garbage. But perversely, the last reference to a first-train object could move around so it is never to the first car. 148 74