PhantomReference wird nicht enqueued



  • Hallo Leute!

    Ich spiele mich gerade ein bisschen mit PhantomReference aus dem java.lang.ref Package herum. Dabei ist mir aufgefallen, dass meine PhantomReference im folgenden Stueck Code nicht enqueued wird, und ich weiss nicht warum.

    import java.lang.ref.*;
    
    public class Main
    {
    	public static void main(String[] args)
    	{
    		ReferenceQueue<Integer> q = new ReferenceQueue<Integer>();
    		new PhantomReference<Integer>(42, q);
    
    		System.gc(); // GC explizit anwerfen um sicher zu gehen
    
    		for(Reference<? extends Integer> ref = null; (ref = q.poll()) != null;)
    			System.out.println(ref); // erzeugt keine Ausgabe
    	}
    }
    

    Schreibe ich das Beispiel so um, dass ich alle PhantomReferences nochmal in einer extra ArrayList speichere...

    import java.lang.ref.*;
    import java.util.ArrayList;
    
    public class Main
    {
    	public static void main(String[] args)
    	{
    		ReferenceQueue<Integer> q = new ReferenceQueue<Integer>();
    		ArrayList<PhantomReference<Integer>> prefs = new ArrayList<PhantomReference<Integer>>();
    
    		prefs.add(new PhantomReference<Integer>(new Integer(42)/* *** */, q));
    
    		System.gc();
    
    		for(Reference<? extends Integer> ref = null; (ref = q.poll()) != null;)
    			System.out.println(ref);
    
    		for(PhantomReference<Integer> pref : prefs)
    			System.out.println(pref.isEnqueued());
    	}
    }
    

    Dann wird die erste Schleife ueber die ReferenceQueue gar nicht durchlaufen, aber die zweite genau einmal und isEnqueued() gibt true zurueck!
    Was ist hier los? Wieso kommen die PhantomReferences nie in die Queue?

    *** Auch interessant: Es macht einen Unterschied, ob hier new Integer(42) oder nur 42 steht. Bei expliziter Form gibt isEnqueued() true zurueck, bei 42 false.

    Gruesse,
    Der Kellerautomat



  • Niemand ne Idee?



  • Kann es sein, dass der Gabage Collector die Referenz aus der Queue entfernt, da auf ihn sonst nicht ver verwiesen wird?

    Ein anderer Grund:
    Java ist doof. Ich erinnere mich, dass die meistene Java VMs Ineteger-Instanzen von -100 bis 100 zwischenspeichern, damit man nicht ständig füt eben solche Zahlen neue Objekte erstellen muss, sondern gleich die aus dem Cache verwedet werden. (zumindest bei der automatischen Konvertierung von int zu Integer oder so) Diese werden eben nicht mehr gelöscht.



  • Oh man,

    42 kann nie phantom reachable werden.



  • Es hat nichts damit zu tun, dass ich Integer verwende. Mit einer anderen Klasse gibts dasselbe Ergebnis.



  • Kellerautomat schrieb:

    Es hat nichts damit zu tun, dass ich Integer verwende. Mit einer anderen Klasse gibts dasselbe Ergebnis.

    Lese mein Satz noch mal, du argumentierst auch vollkommen einandere vorbei, hab ich nie behauptet.



  • Ich verstehe nicht, was du mir sagen moechtest.



  • Ich hab auf den Unterschied geantwortet, eine 42 liegt nicht auf dem Heap und kann daher nicht in irgendeine Form reachable werden. (http://docs.oracle.com/javase/6/docs/api/java/lang/ref/package-summary.html#reachability)



  • Und inwiefern hilft mir das jetzt weiter?!



  • import java.lang.ref.PhantomReference;
    import java.lang.ref.ReferenceQueue;
    
    public class Main {
    
        public static void main(String[] args) 
        { 
            ReferenceQueue<Integer> q = new ReferenceQueue<>(); 
            PhantomReference<Integer> p1 = new PhantomReference<>(new Integer(42), q);
            PhantomReference<Integer> p2 = new PhantomReference<>(42, q);
    
            System.gc(); // GC explizit anwerfen um sicher zu gehen 
    
            // Solch ein Code funktioniert nicht siehe Beschreibung der Klasse PhantomReference
            // Analog PhantomReference.get() ist immer null
    //        for(Reference<? extends Integer> ref = null; (ref = q.poll()) != null;) 
    //            System.out.println(ref); 
    
            // Doch noch ein Hinweis phantom reachable bedeutet das ein Objekt schon finializiert ist
            System.out.println(p1.isEnqueued());
            System.out.println(p2.isEnqueued());
    
            // Aufräumen nicht vergessen
            p1.clear();
            p2.clear();
        } 
    }
    

    Wozu brauchst du Hilfe? Ich würde eher sagen Finger weg von PhantomReference, dann lieber eigenen Mechanismus um Scheduleraufräumarbeiten durchzuführen. Frag mich auch wozu diese Klasse brauchst, die ist doch nur für besondere Anwendungsfälle interessant.



  • Ich will Resourcen wegraeumen damit. Die Idee waere, mittels Reflection die PhantomReference aufzubrechen, um sich das Objekt zu holen, und dann darauf eine cleanup() Methode aufzurufen oder sowas.


Anmelden zum Antworten