Blog
Skip to end of metadata
Go to start of metadata

A java egy régi (1.2-es verziója óta létező) de kevéssé ismert részéhez tartozik a gyenge referencia. Igaz alkalmazási területe is elég szűk, de ha tudjuk, hogy léteznek és mire jók, a megfelelő időben előhúzva a zsebünkből nagyon hasznos tud lenni a java.lang.ref csomag. Ha egy mondatban össze kellene foglalni mi is az a gyenge referencia akkor úgy írnám le, hogy olyan hivatkozás egy objektumra, ami nem akadályozza meg a szemétgyűjtőt (garbage collector), hogy a hivatkozott objektumot kitakarítsa a memóriából. Ahhoz, hogy pontosan megértsük hogy miről is van szó, egy kicsit elő kell vennünk a szemétgyűjtésről tanultakat.

Az alapoknál kezdve, a java nyelvben nem kell foglalkoznunk az objektumok memóriaterületének felszabadításával, a JVM szemétgyűjtője elvégzi ezt helyettünk minden olyan objektumra, ami már nem elérhető az aktuális programfutási szakaszból. Egész pontosan erős referenciával nem elérhető. Nézzünk erős referenciára egy példát:

String süti = new String("kókuszkocka");

Itt a süti egy erős referencia egy String objektumra. Ha a süti kikerül a láthatósági körünkből, vagy null értéket adunk neki (most nem vagyunk éhesek), akkor a szemétgyűjtő bármikor begyűjtheti azt. Fontos azonban, hogy a szemétgyűjtő lusta és nem azonnal szabadítja fel a memóriát, lehet hogy csak akkor szabadítja fel, amikor teljesen elfogy a JVM rendelkezésére álló memória (megtelik a hűtő). Próbáljuk meg visszaszerezni a sütinket, amíg nem késő...

A java.lang.ref csomag háromféle referenciát ad a kezünkbe, ezek erősségi sorrendben a következők:

  • puha (soft)
  • gyenge (weak)
  • fantom (phantom).

Gyenge referencia

Nézzük meg először a gyenge referenciát. Ha ezzel a referenciával hivatkozunk egy objektumra, és az erős referenciákon keresztül már nem elérhető, akkor azt a szemétgyűjtő bármikor megsemmisítheti, de addig amíg ez meg nem történik mi is elérhetjük, és visszaállíthatjuk. Nézzük meg példával:

WeakReference<String> sütiemlék = new WeakReference<String>(süti);
süti = null;

Ekkor - amíg a szemétgyűjtő ki nem söpri a memóriát - a sütiemlék.get() utasítással még elérhetjük a sütinket. Természetesen ekkor beállíthatunk egy (erős) referenciát a sütire, így kiragadva a sütit a GC kezéből. Ha a sütink már megsemmisült null értéket kapunk vissza a get() hívásra:

süti = sütiemlék.get();
if (süti!=null)
   System.out.println(süti);
else
   System.out.println("valaki már megette");
Szép-szép, de a valós életben mire jó ez?
  • Gyorstárak létrehozására: már betöltött de ideiglenes nem kellő nagy méretű fájlokat (pl. képeket) újra előhozhatunk a memóriából, és nem kell újra felolvasnunk azokat a lemezről.
  • Olyan osztályokhoz amiket nem tudunk kiterjeszteni, pl. egy factory-tól kapott, egy adott interfészt megvalósító osztályokhoz rendelhetünk további attribútumokat, úgy hogy ezzel nem tartjuk bent az eredeti objektumokat a memóriában. Ehhez ad további segítséget a weakHashMap amit később tárgyalunk.

Puha referencia

A puha (Soft) referencia hasonlóan működik mint a gyenge referencia, a különbségük mindössze abban rejlik, hogy a puha referencia egyel erősebb kötelék, azaz a GC megpróbálja minél tovább benntartani a hivatkozott objektumot a memóriában. Persze garancia ugyanúgy nincs rá, hogy még megtaláljuk, amikor kell nekünk, de gyorstárak megvalósításához ez a referencia ajánlott. Abban viszont biztosak lehetünk, hogy a program memóriaigényét az így megvalósított cache nem korlátozza, mivel a GC kitakarít minden olyan objektumot amire csak puha referencia hivatkozik mielőtt OutOfMemoryException-t dobna.

Referencia sorok

Ha egy WeakReference objektum egy már megsemmisített objektumra hivatkozik akkor már igazából ő maga is fölöslegessé válik. Azaz a programunknak időről időre érdemes kitakarítania a nem funkcionáló gyenge referenciákat. Ehhez nyújt segítséget a ReferenceQueue. Ha egy gyenge referenciának a konstruktorában megadunk egy ReferenceQueue-t akkor miután az általa hivatkozott objektum elérhetetlenné válik, belekerül a queue-ba. Igazából a WeakHashMap is azon az elven működik, hogy a kulcs elérése előtt leellenőrzi a saját ReferenceQueue-jában hogy nincs-e érvénytelen gyenge referencia, ha van akkor eltávolítja azt.

Fantom referencia

Végül a fantom referencia segítségével a java finalize-t tudjuk „kiterjeszteni”. Segítségével pl. külső erőforrás felszabadításokat végezhetünk . A fantom referencia konstruktorában mindig meg kell adni egy referencia sort. A referencia általa hivatkozott objektum finalize metódusa után, de a memóriából tényleges kikerülése előtt kerül be ebbe a megadott sorba. Ekkor az objektum már törlésre van ítélve és azt nem is lehet visszaállítani, ezt biztosítva a phantomReference get függvénye mindig null értékkel tér vissza. A tényleges törlés azonban csak akkor történik meg ha a phantom reference-nek a clear metódusát meghívjuk. Összefoglalva, ha egy fantom referencia által hivatkozott objektumot a GC fel akar szabadítani akkor meghívja az objektumra a finalize metódust, majd behelyezi a fantom referenciát a megadott referencia sorba, de magát az objektumot csak akkor tudja felszabadítani ha a fantom referenciának meghívják a clear metódusát..

WeakHashMap

A WeakHashMap egy gyenge referenciákat tartalmazó hasznos kis HashMap, azaz a kulcs-érték párból a kulcs egy gyenge referencia, így nem tartja a memóriában a hivatkozott objektumokat. Továbbá kényelmes a használata, mert adatszerkezet automatikusan kitakarítja magából a nem létező hivatkozásokat, azaz ha a kulcs által hivatkozott objektum megszűnik akkor a WeakHashMap-ből a kulcs-érték pár is kitörlődik. Használatánál oda kell figyelni arra, hogy bármikor eltűnhetnek belőle kulcs-érték párok, hisz a GC bármikor takaríthat, illetve a kulcs alapján való érték visszakeresés se triviális minden esetben, hisz ha van egy erős referenciánk a kulcsra, akkor nincs sok értelme az egésznek.

Objektum elérhetősége

A különböző objektumok elérhetőségét a rá hivatkozott referenciák erőssége szerint csoportba tudjuk sorolni. A következő lista felsorolja a különböző elérhetőségi szinteket legerősebbtől kezdve a leggyengébbig:

  • erősen elérhető egy objektum ha hivatkozik rá egy referencia.
  • Puhán (softly) elérhető egy objektum ha nem erősen elérhető de hivatkozik rá egy puha referencia
  • Gyengén elérhető egy objektum ha se nem erősen se nem puhán nem elérhető de hivatkozik rá egy gyenge referencia
  • Fantom elérhető egy objektum ha se nem erősen se nem puhán sem gyengén nem elérhető de hivatkozik rá egy fantom referencia.
  • Nem elérhető egy objektum ha a fenti listában egyik kapcsolódási típus sem igaz rá.

Az idevonatkozó Java API: http://java.sun.com/javase/6/docs/api/java/lang/ref/package-summary.html

      
      
Page viewed times
#trackbackRdf ($trackbackUtils.getContentIdentifier($page) $page.title $trackbackUtils.getPingUrl($page))