aboutsummaryrefslogtreecommitdiff
path: root/files/it/web/javascript/gestione_della_memoria/index.html
blob: d1cd6c4dca925d1c426ff6fc339c22610933d229 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
---
title: Gestione della memoria
slug: Web/JavaScript/Gestione_della_Memoria
translation_of: Web/JavaScript/Memory_Management
---
<div>{{JsSidebar("Advanced")}}</div>

<h2 id="Introduzione">Introduzione</h2>

<p>Alcuni linguaggi di programmazione, come ad esempio C e C++, possiedono funzioni per la gestione della memoria a basso livello come <code>malloc()</code> e <code>free()</code>; in JavaScript l'allocazione e la de-allocazione della memoria (oggetti, stringhe, ecc.) avviene "automaticamente" grazie alla presenza del <em>Garbage Collection</em>. Il termine "automaticamente" è spesso fonte di confusione tra i programmatori JavaScript (e di altri linguaggi ad alto livello) poichè da l'impressione che si possa non preoccuparsi riguardo la gestione della memoria. Questo è un errore!</p>

<h2 id="Ciclo_di_vita_della_memoria">Ciclo di vita della memoria</h2>

<p>A prescindere dal linguaggio di programmazione, il ciclo di vita della memoria è pressappoco sempre lo stesso:</p>

<ol>
 <li>Allocazione della memoria necessaria</li>
 <li>Utilizzo della memoria (scrittura, lettura)</li>
 <li>Rilascio della memoria allocata quando non è più necessaria</li>
</ol>

<p>I primi due punti sono espliciti in tutti i linguaggi; l'ultimo invece è esplicito nei linguaggi a basso livello, mentre il più delle volte implicito nei linguaggi ad alto livello come JavaScript.</p>

<h3 id="Allocazione_in_JavaScript">Allocazione in JavaScript</h3>

<h4 id="Inizializzazione_con_valore">Inizializzazione con valore</h4>

<p>Per evitare che il programmatore debba allocare ogni variabile utilizzata, JavaScript lo fa contestualmente alla dichiarazione:</p>

<pre class="brush: js">var n = 123; // alloca memoria per un numero
var s = "qwerty"; // alloca memoria per una stringa

var o = {
  a: 1,
  b: null
}; // alloca memoria per un oggetto e i valori contenuti

// (come un oggetto) alloca memoria per l'array e i valori contenuti
var a = [1, null, "abra"];

function f(a){
  return a + 2;
} // alloca una funzione (cioè un oggetto invocabile)

// istruzioni più complesse anche allocano un oggetto
someElement.addEventListener('click', function(){
  someElement.style.backgroundColor = 'blue';
}, false);
</pre>

<h4 id="Allocazione_via_chiamata_di_funzione">Allocazione via chiamata di funzione</h4>

<p>La chiamata di alcune funzioni risultano nell'allocazione di un oggetto, come nel seguente esempio:</p>

<pre class="brush: js">var d = new Date();
// alloca un DOM element
var e = document.createElement('div');
</pre>

<p>Alcuni metodi allocano nuovi valori od oggetti:</p>

<pre class="brush: js">var s = "qwerty";
var s2 = s.substr(0, 3); // s2 è una nuova stringa
// Dato che le stringhe sono valori immutabili,
// JavaScript può decidere di non allocare memoria per una nuova stringa,
// ma semplicemente di salvare il range [0, 3].

var a = ["ouais ouais", "nan nan"];
var a2 = ["generation", "nan nan"];
var a3 = a.concat(a2);
// Un nuovo array di 4 elementi, la concatenazione degli elementi di a e a2
</pre>

<h3 id="Utilizzo_dei_valori">Utilizzo dei valori</h3>

<p>Usare i valori in sostanza significa accedere alla memoria allocata. Questo può essere fatto leggendo o scrivendo il valore di una variabile, di una proprietà di un oggetto, o anche semplicemente passando un argomento a una funzione.</p>

<h3 id="Rilascio_della_memoria_quando_non_più_necessaria">Rilascio della memoria quando non più necessaria</h3>

<p>La maggior parte dei problemi riguardo la gestione della memoria arrivano in questa fase; L'impresa più difficile è determinare quando "la memoria allocata non è più necessaria". Ciò si traduce per il programmatore in individuare dove, nel codice, questo pezzo di memoria non risulta più necessario, e quindi liberarlo.</p>

<p>I linguaggi ad alto livello hanno una funzionalità chiamata "Garbage Collector" il cui compito è di seguire l'allocazione e l'uso della memoria così da determinare quando una porzione della memoria allocata non è più necessaria e liberarla automaticamente. Questo processo è un approssimazione dato che il problema generico di conoscere se una porzione di memoria serve o no è <a class="external external-icon" href="http://en.wikipedia.org/wiki/Decidability_%28logic%29">irrisolvibile</a> (non può essere risolto da un algoritmo).</p>

<h2 id="Garbage_Collection">Garbage Collection</h2>

<p>Partendo dal presupposto che il generico problema di sapere dove una determinata porzione di memoria "non serve più" è irrisolvibile, come conseguenza, l'implementazione dei garbege collection sono una restrizione della soluzione del problema generico. Questa sezione illustra le nozioni necessarie a capire il funzionamento dei principali algoritmi che implementano i garbage collection e le loro limitazioni.</p>

<h3 id="Referenze">Referenze</h3>

<p>L'idea principale su cui si basano gli algoritmi di garbage collection sono le <em>referenze</em>. Nel contesto della gestione della memoria, un oggetto è <em>referente</em> di un altro se può accedere a quest'ultimo (sia in modo implicito che esplicito). Ad esempio, un oggetto JavaScript è referente del suo <a href="/en-US/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain">prototype</a> (referenza implicita) e ai valori delle sue proprietà (referenza esplicita).</p>

<p>In questo contesto, il concetto di "oggetto" si estende a qualcosa di molto più ampio rispetto al tradizionale concetto di "oggetto JavaScript" e contiene function scopes (or the global lexical scope).</p>

<h3 id="Reference-counting_garbage_collection">Reference-counting garbage collection</h3>

<p>Quello qui descritto è l'algoritmo di garbage collection più semplice. Esso riduce il problema da "quando un oggetto non serve più" a "quando un oggetto non è più referenziato da nessun altro oggetto". Un oggetto è considerato garbage collectable (letteralmente, spazzatura da raccogliere) se nessun altro oggetto ha almeno una referenza ad esso.</p>

<h4 id="Esempio">Esempio</h4>

<pre class="brush: js">var o = {
  a: {
    b:2
  }
};
// Alloca 2 oggetti. Il primo è referenziato dall'altro come sua proprietà.
// L'altro è referenziato dalla <s>dalla virtù di essere assegnato alla</s> variabile 'o'.
// Ovviamente, nessuno dei due può essere cancellato per liberare memoria


var o2 = o; // la variabile 'o2' è il secondo oggetto
            // che referenzia lo stesso oggetto di 'o'
o = 1;      // ora l'oggetto che originariamente era in 'o' ha un'unica referenza
            // rappresentata dalla variabile 'o2'

var oa = o2.a; // referenza alla proprietà 'a' dell'oggetto.
               // Quest'oggetto ora ha 2 referenze: una come proprietà di 'o2'
               // e una come variabile 'oa'

o2 = "yo"; // L'oggetto che originariamente era in 'o' adesso non
           // più alcuna referenza e può essere cancellato.
           // Però la sua proprietà 'a' è ancora referenziata
           // dall'oggetto 'oa', quindi non può essere ancora eliminato

oa = null; // la proprietà 'a' del precedente oggetto adesso non ha
           // alcuna referenza. Può essere cancellata.
</pre>

<h4 id="Limitazione_cicli_di_referenze">Limitazione: cicli di referenze</h4>

<p>Questo algotitmo ha una limitazione quando entra in un ciclo di referenze. Nell'esempio seguente sono creati due oggetti che si referenziano a vicenda, uno referenzia l'altro e viceversa, creando un ciclo di referenze (dipendenza ciclica). In questo modo ogni oggetto ha almento una referenza, l'algoritmo del reference-countig (ovvero quello che "conta" quante referenze ha un oggetto) da come risultato che nessuno dei due oggetti può essere cancellato (non sono garbage-collactable).</p>

<pre class="brush: js">function f(){
  var o = {};
  var o2 = {};
  o.a = o2; // o referenzia o2
  o2.a = o; // o2 referenzia o

  return "qwerty";
}

f();
// Two objects are created and reference one another thus creating a cycle.
// They will not get out of the function scope after the function call, so they
// are effectively useless and could be free'd.
// However, the reference-counting algorithm considers that since each of both
// object is referenced at least once, none can be garbage-collected.
</pre>

<h4 id="Esempio_reale">Esempio reale</h4>

<p>Internet Explorer 6 e 7 sono conosciuti per avere un <em>reference-counting garbage collector</em> per gli oggetti DOM. I cicli di referenze sono errori comuni che possono generare uno spreco di memoria (memory leaks).</p>

<pre class="brush: js">var div;
window.onload = function(){
  div = document.getElementById("myDivElement");
  div<span style="font-size: 1rem;">.circularReference = div;</span>
  div.lotsOfData = new Array(10000).join("*");
};
</pre>

<p>Nell'esempio precedente, l'elemento "myDivElement" ha una referenza circolare con se stesso nella proprietà "circularReference". Se la proprietà non è esplicitamente rimossa o annullata, un <em>reference-counting garbage collector </em>avrà sempre almeno una referenza intatta che manterrà l'elemento in memoria anche se esso fosse rimosso dal DOM. Se un oggetto trattiene molta memoria e ha almeno una referenza (come illustrato nell'esempio precedente con la proprietà "lotsOfData") la memoria da esso occupata non sarà mai rilasciata.</p>

<h3 id="L'algoritmo_mark-and-sweep">L'algoritmo mark-and-sweep</h3>

<p>Questo algoritmo è il più famoso degli algoritmi di tracing; la tecnica del tracing è concettualmente molto semplice e si basa sulla definizione "quando un oggetto diventa irraggiungibile".</p>

<p>Essa consiste nel prendere come riferimento gli oggetti root (indice dell'albero) e, partendo da essi, mediante una ricorsione, marcare (tramite un bit o una mappa distinta) tutti gli oggetti collegati tra loro da un riferimento. Al termine di questa operazione, gli oggetti raggiungibili saranno marcati mentre quelli non raggiungibili saranno eliminati.</p>

<p>L'algoritmo mark-and-sweep (marca e butta via) si suddivide in due fasi: la prima fase (<em>mark</em>) nella quale l'algoritmo marca tutti gli oggetti che hanno almeno un riferimento attivo; nella seconda fase (<em>sweep</em>) nella quale tutti gli oggetti non marcati vengono liberati e la memoria viene restituita.</p>

<p>A differenza della tecnica del reference counting il cui il costo dell'algoritmo è proporzionale all'ammontare del lavoro eseguito dal programma (ogni volta che si alloca/dealloca un oggetto bisogna creare-incrementare/decrementare il contatore), la tecnica del tracing è proporzionale alla dimensione della memoria ed è sicuramente più efficiente.</p>

<h4 id="I_cicli_non_sono_più_un_problema">I cicli non sono più un problema</h4>

<p>Nel primo esempio, dopo che la funzione ha restituito un risultato, i 2 oggetti non sono più referenziati da nessun altro oggetto raggiungibile dall'oggetto globale (root). Ne consegue che saranno irraggiungibili dal garbage collector e quindi eleminati.</p>

<p>La stessa cosa accade con il secondo esempio. Una volta che il div e la sua variabile sono diventati irraggiungibili dalle radici, essi possono essere cancellati nonostante abbiano una referenza ciascuno.</p>

<h4 id="Limitazione_gli_oggetti_devono_essere_esplicitamente_irragiungibili">Limitazione: gli oggetti devono essere esplicitamente irragiungibili</h4>

<p>Sebbene sia marcata come una limitazione, è raramente raggiunta in pratica ed è anche il motivo per cui nessuno si preoccupa, di solito, dei garbage collector.</p>

<blockquote>
<h4 id="Piccolo_appunto_italiano">Piccolo appunto italiano</h4>

<p>Tutte le parole <s>tagliate</s> sono state tradotte letteralmente ma in modo che la frase non perda di significato.</p>

<p dir="rtl">cit. Il traduttore</p>
</blockquote>

<h2 id="See_also">See also</h2>

<ul>
 <li><a class="external" href="http://www.ibm.com/developerworks/web/library/wa-memleak/">IBM article on "Memory leak patterns in JavaScript" (2007)</a></li>
 <li><a class="external" href="http://msdn.microsoft.com/en-us/magazine/ff728624.aspx">Kangax article on how to register event handler and avoid memory leaks (2010)</a></li>
 <li><a href="https://developer.mozilla.org/en-US/docs/Mozilla/Performance" title="https://developer.mozilla.org/en-US/docs/Mozilla/Performance">PerformancC</a></li>
</ul>