Jedna od velikih gresaka koju prave programeri jezika sa automatskim ciscenjem memorije je sledeca:
Neuklanjanje starih i beskorisnih referenci
Pogledajmo primer:
Code:
public class Stack
{
private SomeClass[] elements;
private int top;
private int capacity;
public Stack(int capacity)
{
this.capacity = capacity
elements = new SomeClass[capacity];
top = 0;
}
public Push(SomeClass newElement)
{
if (top == capacity - 1)
{
SomeClass[] temp = elements;
capacity *= 2;
elements = new SomeClass[capacity];
Array.Copy(temp, elements, capacity);
}
elements[++top] = newElement;
}
public SomeClass Pop()
{
if (top < capacity / 2)
{
SomeClass[] temp = elements;
capacity /= 2;
elements = new SomeClass[capacity];
Array.Copy(temp, elements, capacity);
}
return elements[top--];
}
}
Naizgled metoda Pop je potpuno u redu.
Ali zamislimo situaciju da smo inicirali kapacitet od oko 1000 elemenata.
Pritom smo dodali oko 1900 i stek je uzeo 2000 referenci.
Sada zamislimo da smo pokupili sa steka oko 800 elemenata.
Sada imamo na steku oko 1100 elemenata, ali i onih 800 sto nismo dereferencirali.
Tako da ako bi se na steku vrteo broj elemenata oko 1100, onih 800 bi bez veze opterecivali memoriju.
Sada zamislimo da nije u pitanju 1000 i 2000 objekata, nego 100.000 i 200.000.
Desavalo bi se da izbaci exception za prekoracenje memorije,
da ne pricam o tome da se ovakva komponenta koristi na vise mesta.
pogledajmo izmenjenu verziju metode Pop
Code:
public SomeClass Pop()
{
if (top < capacity / 2)
{
SomeClass[] temp = elements;
capacity /= 2;
elements = new SomeClass[capacity];
Array.Copy(temp, elements, capacity);
}
SomeClass temp = elements[top];
elements[top] = null; // Garbage collector ce se pobrinuti da ukloni beskorisnu referencu
top--;
return temp;
}
U izmenjenoj verziji ce se garbage collector pobrinuti da ocisti referencu koju ne koristimo i tako oslobodi memoriju.