Frage

Phantom Referenzen dienen für post-mortem-Operationen. Die Java-Spezifikation besagt, dass ein Phantom referenzierte Objekt wird nicht bis zur Phantom-Referenz freigegeben wird selbst gereinigt wird.

Meine Frage ist: Welchen Zweck hat diese Funktion (Objekt nicht freigegeben) dienen

(Die einzige Idee, die ich mit aufkommen, ist nativen Code zu ermöglichen, post-mortem Bereinigung auf dem Objekt zu tun, aber es ist nicht viel überzeugend).

War es hilfreich?

Lösung

Die einzige gute Use-Case ich mich vorstellen kann, dass Deallokation verhindern würde, ist eine, wo eine Art von JNI-implementiertes asynchroner Datenquelle in das referenzierte Objekt zu schreiben, und muß zurücktreten gesagt werden - zu stoppen, in dem Schreiben das Objekt - bevor der Speicher zurückgeführt wird. Wenn vor Aufhebung der Zuordnung erlaubt wurden, ein einfaches Passwort-to-dispose () Fehler im Speicherbeschädigung führen könnte.

Dies ist einer der Fälle, in denen finalize () verwendet wurden in der Vergangenheit würde, und fuhr wahrscheinlich einige seiner Macken.

Andere Tipps

Bearbeiten, da ich habe die Frage falsch verstanden zuerst:

von hier Zitiert http://www.memorymanagement.org/glossary/p.html

  

Die Java-Spezifikation besagt, dass die   Phantom Referenz wird nicht gelöscht, wenn   das Referenzobjekt wird die Warteschlange eingereiht, aber   tatsächlich gibt es keine Möglichkeit, in der   Sprache zu sagen, ob das hat   getan oder nicht. In einigen Implementierungen   JNI weltweit schwache Referenzen sind schwächer   als Phantom Referenzen, und bieten eine   Art und Weise Phantom erreichbar zugreifen   Objekte.

Aber ich fand keine anderen Hinweise, die das gleiche sagen würde.

Ich denke, die Idee ist, andere Objekte über und darüber hinaus zusätzliche Bereinigung tun zu lassen, was das ursprüngliche Objekt der Fall ist. wenn das ursprüngliche Objekt nicht erweitert werden kann, zum Beispiel einer Finalisierung Sachen zu implementieren, können Sie Phantom Referenzen verwenden.

Das größere Problem ist, dass die JVM keine Garantie machen, dass ein Objekt jemals abgeschlossen sein wird, und ich gehe davon durch die Erweiterung keine Garantie, dass Phantom Referenzen ihre Sache nach Fertigstellung zu tun bekommen.

Phantom Referenzen können verwendet werden, pre-Garbage-Collection-Aktionen wie Freigabe von Ressourcen auszuführen. Verwenden Sie stattdessen Menschen in der Regel die Finalisierung () -Methode für diese, die keine gute Idee ist. Finalizers haben eine schreckliche Auswirkungen auf die Performance des Garbage Collector und kann die Datenintegrität Ihrer Anwendung brechen, wenn Sie da die „Finalizerthread“ nicht sehr vorsichtig sind in einem zufälligen Thread aufgerufen wird, zu einem beliebigen Zeitpunkt.
Im Konstruktor eines Phantoms Referenz geben Sie eine Reference wo die Phantom Referenzen die Warteschlange gestellt werden, sobald die referenzierte Objekte „Phantom erreichbar“ wird. Phantom erreichbar bedeutet nicht erreichbar andere Weise als durch die Phantom Referenz. Die anfänglich verwirrende Sache ist, dass, obwohl das Phantom Referenz das referenzierte Objekt in einem privaten Bereich (im Gegensatz zu weichen oder schwachen Verweis) halten weiterhin, seine getReference () Methode immer null zurück. Dies ist so, dass Sie das Objekt nicht machen können stark wieder erreichbar.
Von Zeit zu Zeit können Sie die Reference abfragen und überprüfen, ob es irgendwelche neuen PhantomReferences deren referenzierte Objekte sind, haben Phantom erreichbar geworden. Um zu etwas in der Lage sein nützlich, kann man beispielsweise leiten Sie eine Klasse von java.lang.ref.PhantomReference dass Referenzen Ressourcen, die vor der Garbage Collection freigegeben werden sollen. Das referenzierte Objekt wird nur Müll gesammelt, sobald das Phantom Referenz selbst nicht mehr erreichbar ist.

http://www.javalobby.org/java/forums/m91822870 .html # 91822413

Dies ist eine perfekte Lösung für die APIs, die nicht einen Lifecycle-Management-Mechanismus, aber die Sie mit etwas implementieren, die explizite Lifecycle Management erfordert.

Insbesondere jede Art von API, die nur Objekte im Speicher verwenden zu verwenden, die man aber neu implementiert haben eine Socket-Verbindung oder eine Datei Verbindung zu einem anderen, größeren Zusatzspeicher verwenden, können PhantomReference verwenden „close“ und Bereinigung von Verbindungsinformationen vor dem Objekt GC'd und die Verbindung ist nie, weil es geschlossen keine Lifecycle-Management-API war Schnittstelle, die Sie könnten sonst verwenden.

Denken Sie eine einfache Karte Karte in eine Datenbank zu bewegen. Wenn die Karte Referenz verworfen wird, gibt es keinen expliziten „close“ Betrieb. Doch wenn Sie einen Schreib durch Cache implementiert hatten, dann würden Sie gerne in der Lage sein, alle Schreibvorgänge zu beenden und schließen Sie die Socket-Verbindung zur Ihrer „Datenbank“.

Im Folgenden finden Sie eine Klasse, die ich für diese Art von Sachen verwenden. Beachten Sie, dass Verweise auf PhantomReferences müssen nicht lokale Referenzen korrekt zu arbeiten. Andernfalls wird bewirken, dass der JIT sie vorzeitig vor dem Beenden Codeblöcken der Warteschlange werden.

    import java.lang.ref.PhantomReference;
    import java.lang.ref.Reference;
    import java.lang.ref.ReferenceQueue;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.atomic.AtomicInteger;
    import java.util.logging.Level;
    import java.util.logging.Logger;

    /**
     * This class provides a way for tracking the loss of reference of one type of
     * object to allow a secondary reference to be used to perform some cleanup
     * activity.  The most common use of this is with one object which might
     * contain or refer to another object that needs some cleanup performed
     * when the referer is no longer referenced.
     * 

* An example might be an object of type Holder, which refers to or uses a * Socket connection. When the reference is lost, the socket should be * closed. Thus, an instance might be created as in *

     *    ReferenceTracker trker = ReferenceTracker() {
     *        public void released( Socket s ) {
     *            try {
     *                s.close();
     *            } catch( Exception ex ) {
     *                log.log( Level.SEVERE, ex.toString(), ex );
     *            }
     *        }
     *  };
     * 
* Somewhere, there might be calls such as the following. *
     *        interface Holder {
     *            public T get();
     *        }
     *        class SocketHolder implements Holder {
     *            Socket s;
     *            public SocketHolder( Socket sock ) {
     *                s = sock;
     *            }
     *            public Socket get() {
     *                return s;
     *            }
     *        }
     * 
* This defines an implementation of the Holder interface which holds * a reference to Socket objects. The use of the trker * object, above, might then include the use of a method for creating * the objects and registering the references as shown below. *
     *    public SocketHolder connect( String host, int port ) throws IOException {
     *        Socket s = new Socket( host, port );
     *        SocketHolder h = new SocketHolder( s );
     *        trker.trackReference( h, s );
     *        return h;
     *    }
     * 
* Software wishing to use a socket connection, and pass it around would * use SocketHolder.get() to reference the Socket instance, in all cases. * then, when all SocketHolder references are dropped, the socket would * be closed by the released(java.net.Socket) method shown * above. *

* The {@link ReferenceTracker} class uses a {@link PhantomReference} to the first argument as * the key to a map holding a reference to the second argument. Thus, when the * key instance is released, the key reference is queued, can be removed from * the queue, and used to remove the value from the map which is then passed to * released(). */ public abstract class ReferenceTracker { /** * The thread instance that is removing entries from the reference queue, refqueue, as they appear. */ private volatile RefQueuePoll poll; /** * The Logger instance used for this instance. It will include the name as a suffix * if that constructor is used. */ private static final Logger log = Logger.getLogger(ReferenceTracker.class.getName()); /** * The name indicating which instance this is for logging and other separation of * instances needed. */ private final String which; /** * Creates a new instance of ReferenceTracker using the passed name to differentiate * the instance in logging and toString() implementation. * @param which The name of this instance for differentiation of multiple instances in logging etc. */ public ReferenceTracker( String which ) { this.which = which; } /** * Creates a new instance of ReferenceTracker with no qualifying name. */ public ReferenceTracker( ) { this.which = null; } /** * Provides access to the name of this instance. * @return The name of this instance. */ @Override public String toString() { if( which == null ) { return super.toString()+": ReferenceTracker"; } return super.toString()+": ReferenceTracker["+which+"]"; } /** * Subclasses must implement this method. It will be called when all references to the * associated holder object are dropped. * @param val The value passed as the second argument to a corresponding call to {@link #trackReference(Object, Object) trackReference(T,K)} */ public abstract void released( K val ); /** The reference queue for references to the holder objects */ private final ReferenceQueuerefqueue = new ReferenceQueue(); /** * The count of the total number of threads that have been created and then destroyed as entries have * been tracked. When there are zero tracked references, there is no queue running. */ private final AtomicInteger tcnt = new AtomicInteger(); private volatile boolean running; /** * A Thread implementation that polls {@link #refqueue} to subsequently call {@link released(K)} * as references to T objects are dropped. */ private class RefQueuePoll extends Thread { /** * The thread number associated with this instance. There might briefly be two instances of * this class that exists in a volatile system. If that is the case, this value will * be visible in some of the logging to differentiate the active ones. */ private final int mycnt; /** * Creates an instance of this class. */ public RefQueuePoll() { setDaemon( true ); setName( getClass().getName()+": ReferenceTracker ("+which+")" ); mycnt = tcnt.incrementAndGet(); } /** * This method provides all the activity of performing refqueue.remove() * calls and then calling released(K) to let the application release the * resources needed. */ public @Override void run() { try { doRun(); } catch( Throwable ex ) { log.log( done ? Level.INFO : Level.SEVERE, ex.toString()+": phantom ref poll thread stopping", ex ); } finally { running = false; } } private volatile boolean done = false; private void doRun() { while( !done ) { Reference ref = null; try { running = true; ref = refqueue.remove(); K ctl; synchronized( refmap ) { ctl = refmap.remove( ref ); done = actCnt.decrementAndGet() == 0; if( log.isLoggable( Level.FINE ) ) { log.log(Level.FINE, "current act refs={0}, mapsize={1}", new Object[]{actCnt.get(), refmap.size()}); } if( actCnt.get() != refmap.size() ) { Throwable ex = new IllegalStateException("count of active references and map size are not in sync"); log.log(Level.SEVERE, ex.toString(), ex); } } if( log.isLoggable( Level.FINER ) ) { log.log(Level.FINER, "reference released for: {0}, dep={1}", new Object[]{ref, ctl}); } if( ctl != null ) { try { released( ctl ); if( log.isLoggable( Level.FINE ) ) { log.log(Level.FINE, "dependant object released: {0}", ctl); } } catch( RuntimeException ex ) { log.log( Level.SEVERE, ex.toString(), ex ); } } } catch( Exception ex ) { log.log( Level.SEVERE, ex.toString(), ex ); } finally { if( ref != null ) { ref.clear(); } } } if( log.isLoggable( Level.FINE ) ) { log.log(Level.FINE, "poll thread {0} shutdown for {1}", new Object[]{mycnt, this}); } } } /** * A count of the active references. */ private final AtomicInteger actCnt = new AtomicInteger(); /** * Map from T References to K objects to be used for the released(K) call */ private final ConcurrentHashMap,K>refmap = new ConcurrentHashMap,K>(); /** * Adds a tracked reference. dep should not refer to ref in any way except possibly * a WeakReference. dep is almost always something referred to by ref. * @throws IllegalArgumentException of ref and dep are the same object. * @param dep The dependent object that needs cleanup when ref is no longer referenced. * @param ref the object whose reference is to be tracked */ public void trackReference( T ref, K dep ) { if( ref == dep ) { throw new IllegalArgumentException( "Referenced object and dependent object can not be the same" ); } PhantomReference p = new PhantomReference( ref, refqueue ); synchronized( refmap ) { refmap.put( p, dep ); if( actCnt.getAndIncrement() == 0 || running == false ) { if( actCnt.get() > 0 && running == false ) { if (log.isLoggable(Level.FINE)) { log.fine("starting stopped phantom ref polling thread"); } } poll = new RefQueuePoll(); poll.start(); if( log.isLoggable( Level.FINE ) ) { log.log( Level.FINE, "poll thread #{0} created for {1}", new Object[]{tcnt.get(), this}); } } } } /** * This method can be called if the JVM that the tracker is in, is being * shutdown, or someother context is being shutdown and the objects tracked * by the tracker should now be released. This method will result in * {@link #released(Object) released(K) } being called for each outstanding refernce. */ public void shutdown() { Listrem; // Copy the values and clear the map so that released // is only ever called once, incase GC later evicts references synchronized( refmap ) { rem = new ArrayList( refmap.values() ); refmap.clear(); } for( K dep : rem ) { try { released( dep ); } catch( Exception ex ) { log.log( Level.SEVERE, ex.toString(), ex ); } } } }

Es kann ermöglicht es Ihnen, zwei Phantom-Caches haben, die in der Speicherverwaltung sehr effizient sind. Einfach gesagt, wenn Sie große Objekte haben, die aber selten verwendet zu schaffen teuer sind, können Sie ein Phantom-Cache sie zu verweisen verwenden und sicherzustellen, dass sie Speicher benötigen Sie nicht, dass mehr wert ist. Wenn Sie regelmäßig Referenzen verwenden müssen Sie manuell sicher, es machen werden, sind keine Verweise auf das Objekt verlassen. Sie können das gleiche zu jedem Objekt argumentieren, aber Sie müssen nicht manuell die Referenzen in Ihrer Phantom-Cache verwalten. muss nur vorsichtig sein, zu überprüfen, ob sie erhoben wurden oder nicht.

Sie können auch einen Rahmen (das heißt eine Fabrik) verwenden, wo Referenzen als Phantomnummer angegeben ist. Dies ist nützlich, wenn die Objekte sind vielfältig und von kurzer Dauer (d verwendet und dann entsorgt werden). Sehr praktisch für Speicher löschen, wenn Sie schlampig Programmierer haben die Garbage Collection denken ist magisch.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top