Hallo allemaal,
Ik ben een collectie (een priority queue, die het efficient verwijderen van een element (log n) en het efficient verlagen/verhogen van de key van een element (log n) ondersteunt) aan het implementeren. Ik geef even een fragment van de implementatie (een aantal dingen zijn weggelaten, voor de eenvoud):
De gebruiker voegt dus een willekeurig object toe aan de collectie, en krijgt een Element-object terug, hetgeen zijn gegeven object bevat. Vanaf dan moet de gebruiker verder werken met het Element-object. Op die manier kan ik efficient verwijderen ondersteunen.
Hoewel dit allemaal perfect werkt, heeft deze implementatie één groot nadeel: MijnCollectieElement is niet static. Dit betekent dat een element (MijnCollectieElement) impliciet een referentie heeft naar zijn collectie (MijnCollectie). Wanneer de gebruiker zijn referentie naar de collectie op null zet, maar nog ergens (minstens) 1 referentie naar een element heeft, wordt de collectie nooit opgeruimd door de garbage collectie: het element bevat nog steeds een bereikare referentie naar de collectie. Dit toon ik even in volgend fragment:
Waarom is MijnCollectieElement niet static? Ik moet kunnen controleren of een gegeven Element wel degelijk door de collectie in kwestie is aangemaakt. Het is natuurlijk niet de bedoeling dat de gebruiker een element aangemaakt door collectie A als parameter aan een functie van een collectie B kan gegeven. Zie remove() in MijnCollectie.
Ik heb hiervoor een oplossing gevonden: WeakReference. Ik maak MijnCollectieElement static, en hou een referentie naar de collectie bij aan de hand van een WeakReference. Wanneer de gebruiker zijn referentie naar de collectie verliest, wordt de collectie nu wel opgeruimd door de garbage collector. Hier zijn de aanpassingen:
Wat is het probleem nu? In principe is er helemaal geen probleem: het werkt perfect! In het voorbeeld hierboven wordt de collectie nu wel opgeruimd. Maar ik ben niet helemaal zeker of dit een goede en mooie oplossing is. Ik vind het 'verdacht' dat ik MijnCollectieElement static heb moeten maken, en expliciet een referentie naar zijn collectie moet bijhouden. Daarom had ik graag van de java experts op dit forum geweten wat zij van deze oplossing vinden
Ik ben dus op zoek naar een oplossing waarmee:
- we kunnen weten of een element aangemaakt is door de collectie waaraan het element gegeven wordt; en
- de collectie door de garbage collectie kan opgeruimd worden, zonder dat eerst alle elementen zelf opgeruimd moeten worden.
Opmerking: Ik heb er ook aan gedacht om in MijnCollectie een HashSet<MijnCollectieElement> bij te houden, die de geldige/actieve elementen bijhoudt. Op die manier kan ik ook snel controleren of een gegeven Element geldig is. Ik ben tegen deze oplossing, omdat:
- een HashSet aardig wat geheugen gebruikt, en de bedoeling van mijn eigen implementatie is om het geheugengebruik zo laag mogelijk te houden; en
- het in principe onwaarschijnlijk is dat de gebruiker elementen aan een andere collectie gaat geven dan diegene die het element gemaakt heeft.
hopelijk was ik duidelijk genoeg
bedankt voor de hulp
Ik ben een collectie (een priority queue, die het efficient verwijderen van een element (log n) en het efficient verlagen/verhogen van de key van een element (log n) ondersteunt) aan het implementeren. Ik geef even een fragment van de implementatie (een aantal dingen zijn weggelaten, voor de eenvoud):
Java:
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
| interface Element <E> { E getElement(); } class MijnCollectie <E> { private MijnCollectieElement[] elements; private int size = 0; public MijnCollectie(int size) { elements = new MijnCollectieElement[size]; } public Element<E> add(E element) { MijnCollectieElement e = new MijnCollectieElement(element); elements[size++] = e; return e; } public void remove(Element<E> element) { /* controleer of element aangemaakt is door deze collectie */ if (!(element instanceof MijnCollectieElement)) { throw new RuntimeException(); // niet aangemaakt door deze collectie } MijnCollectieElement e = (MijnCollectieElement) element; if (e.getCollectie() != this) { throw new RuntimeException(); // niet aangemaakt door deze collectie } // ... } private class MijnCollectieElement implements Element { private E element; public MijnCollectieElement(E element) { this.element = element; } public E getElement() { return element; } public MijnCollectie getCollectie() { return MijnCollectie.this; } } } |
De gebruiker voegt dus een willekeurig object toe aan de collectie, en krijgt een Element-object terug, hetgeen zijn gegeven object bevat. Vanaf dan moet de gebruiker verder werken met het Element-object. Op die manier kan ik efficient verwijderen ondersteunen.
Hoewel dit allemaal perfect werkt, heeft deze implementatie één groot nadeel: MijnCollectieElement is niet static. Dit betekent dat een element (MijnCollectieElement) impliciet een referentie heeft naar zijn collectie (MijnCollectie). Wanneer de gebruiker zijn referentie naar de collectie op null zet, maar nog ergens (minstens) 1 referentie naar een element heeft, wordt de collectie nooit opgeruimd door de garbage collectie: het element bevat nog steeds een bereikare referentie naar de collectie. Dit toon ik even in volgend fragment:
Java:
1
2
3
4
5
6
7
8
| MijnCollectie<EenGrootObject> c = new MijnCollectie<EenGrootObject>(10000); for (int i = 0; i < 10000 - 1; i++) { c.add(new EenGrootObject()); } Element<EenGrootObject> e = c.add(new EenGrootObject()); c = null; /* de collectie wordt niet opgeruimd door de garbage collectie, omdat er nog een referentie naar de collectie bestaat via e */ |
Waarom is MijnCollectieElement niet static? Ik moet kunnen controleren of een gegeven Element wel degelijk door de collectie in kwestie is aangemaakt. Het is natuurlijk niet de bedoeling dat de gebruiker een element aangemaakt door collectie A als parameter aan een functie van een collectie B kan gegeven. Zie remove() in MijnCollectie.
Ik heb hiervoor een oplossing gevonden: WeakReference. Ik maak MijnCollectieElement static, en hou een referentie naar de collectie bij aan de hand van een WeakReference. Wanneer de gebruiker zijn referentie naar de collectie verliest, wordt de collectie nu wel opgeruimd door de garbage collector. Hier zijn de aanpassingen:
Java:
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
| class MijnCollectie <E> { private MijnCollectieElement[] elements; private int size = 0; public MijnCollectie(int size) { elements = new MijnCollectieElement[size]; } public Element<E> add(E element) { MijnCollectieElement<E> e = new MijnCollectieElement<E>(element, this); elements[size++] = e; return e; } public void remove(Element<E> element) { /* controleer of element aangemaakt is door deze collectie */ if (!(element instanceof MijnCollectieElement)) { throw new RuntimeException(); // niet aangemaakt door deze collectie } MijnCollectieElement e = (MijnCollectieElement) element; if (e.getCollectie() != this) { throw new RuntimeException(); // niet aangemaakt door deze collectie } // ... } private static /* ADDED */ class MijnCollectieElement<E> extends WeakReference<MijnCollectie> /* ADDED */ implements Element<E> { private E element; public MijnCollectieElement(E element, MijnCollectie c) { super(c); this.element = element; } public E getElement() { return element; } public MijnCollectie getCollectie() { return get(); } } } |
Wat is het probleem nu? In principe is er helemaal geen probleem: het werkt perfect! In het voorbeeld hierboven wordt de collectie nu wel opgeruimd. Maar ik ben niet helemaal zeker of dit een goede en mooie oplossing is. Ik vind het 'verdacht' dat ik MijnCollectieElement static heb moeten maken, en expliciet een referentie naar zijn collectie moet bijhouden. Daarom had ik graag van de java experts op dit forum geweten wat zij van deze oplossing vinden
Ik ben dus op zoek naar een oplossing waarmee:
- we kunnen weten of een element aangemaakt is door de collectie waaraan het element gegeven wordt; en
- de collectie door de garbage collectie kan opgeruimd worden, zonder dat eerst alle elementen zelf opgeruimd moeten worden.
Opmerking: Ik heb er ook aan gedacht om in MijnCollectie een HashSet<MijnCollectieElement> bij te houden, die de geldige/actieve elementen bijhoudt. Op die manier kan ik ook snel controleren of een gegeven Element geldig is. Ik ben tegen deze oplossing, omdat:
- een HashSet aardig wat geheugen gebruikt, en de bedoeling van mijn eigen implementatie is om het geheugengebruik zo laag mogelijk te houden; en
- het in principe onwaarschijnlijk is dat de gebruiker elementen aan een andere collectie gaat geven dan diegene die het element gemaakt heeft.
hopelijk was ik duidelijk genoeg