i actually got a copy of the book and i thought that if some one could provide me a piece of code or something maybe i can understand better. Thanks Botella. if possible try posting a sample code like.
say,
Class MyClass
{
MyOldClass moc;
its easier to understand that way.
the above code fragment i know that moc is a strong reference and thats obvious. but the distinction between weak and phanthom in particular is elusive for me.
thanks all in advance
G.P.
import java.lang.ref.*;
import java.util.WeakHashMap;
class Phantom {
protected void finalize() {
System.out.println("A phantom is being finalized");
}
}
class References {
public static void main(String[] args) throws
InterruptedException {
String key1 = new String("1");
WeakHashMap whm = new WeakHashMap();
whm.put(key1, new Integer(1));
whm.put(new String("2"), new Integer(2));
whm.put(new String("3"), new Integer(3));
System.out.println(whm);
System.gc();
System.out.println(whm);
///////////////////////////
ReferenceQueue rq = new ReferenceQueue();
PhantomReference pr =
new PhantomReference(new Phantom(), rq);
pr.enqueue();
System.gc();
Reference ref = rq.poll();
if (ref!=null) System.out.println(ref);
//Do any finalization non related to the phantom object
pr.clear();
}
}
I have no time to comment the code now I want to watch Aly McBeal
Tomorrow I will do it.
I am commenting only the second part of the program now.
This is how I thought PhantomRefrences (phanref from now) worked:
Once an object is reachable only through phanrefs and the collector has executed its finalize methods, the collector enqueues the phanref.
A program that would want to do pre-morten actions in a more flexible way than with the finalize method, could check periodically if this the phanref has been enqueued via poll() or remove(). Now it could perform the needed actions itself, without the danger of a collector not executing the finalize methods.
When these actions are finished, the program calls clear() and the phanref deletes their reference to the object whose memory could be reclaimed.
Fortunately I still think this is true.
So why my first try, which is identical to the previous code but without pr.enqueue(), didn't work?
Well, because the collector seems not able to run all the finalize method and call enqueue() in the same pass.
I put pr.enqueue() and the program worked. But I am not happy with that because if the program tests the queue before the run of the collector, it would be doing the pre-morten actions on an unfinalized object.
Maybe a solution would be check, besides testing the queue, an static boolean set by the finalize method.
Another solution would be wait, if possible, two runs of the collector
If the collector is executed twice, the object would be collected, and the pre-morten actions would be done after the second run. This second pass is able to enqueue the phanref because the finalize methods has been executed by the first. This program shows it:
import java.lang.ref.*;
class Phantom {
protected void finalize() {
System.out.println("A phantom is being finalized");
}
}
class References2 {
public static void main(String[] args) throws
InterruptedException {
ReferenceQueue rq = new ReferenceQueue();
PhantomReference pr = new PhantomReference(new Phantom(), rq);
System.gc();
Reference ref = rq.remove(5000);
checkRef(ref, " first call", pr);
System.gc();
ref = rq.remove(5000);
checkRef(ref, " second call", pr);
}
static void checkRef(Reference ref, String s, PhantomReference pr) {
System.out.println(s);
if (ref!=null) {
System.out.println(ref);
//Do any finalization non related to the phantom object
pr.clear();
}
}
}
the output:
A phantom is being finalized
first call
second call
java.lang.ref.PhantomReference@273d3c
Also it is possible to enqueue the phanref at the end of the finalize method, as this program shows:
import java.lang.ref.*;
class Phantom {
PhantomReference pr;
void setPhantomRef(PhantomReference pr) { this.pr = pr; }
protected void finalize() {
System.out.println("A phantom is being finalized");
pr.enqueue();
}
}
class References3 {
public static void main(String[] args) {
ReferenceQueue rq = new ReferenceQueue();
Phantom p = new Phantom();
PhantomReference pr = new PhantomReference(p, rq);
p.setPhantomRef(pr);
p = null;
System.gc();
Reference ref = rq.poll();
if (ref!=null) {
System.out.println(ref);
//Do any finalization non related to the phantom object
pr.clear();
}
}
}
Which technique is better?
Well the last, and the one that checks a boolean set by finalize, are not very clever if we are afraid of a collector being unable to execute the finalize methods.
Now my question. If the advantage of using a phanref instead of finalize is not the movement of the code from the finalize to the program itself, which it is?. It can not be the prohibition for the finalize methods to resurrect an object because, one that is referenced only by a phanref can not be resurrected.
> Once an object is reachable only through phanrefs and
> the collector has executed its finalize methods, the
I meant "method"
> I put pr.enqueue() and the program worked. But I am
> not happy with that because if the program tests the
> queue before the run of the collector, it would be
> doing the pre-morten actions on an unfinalized
> object.
Where is the problem if there is not finalize method at all for the object?
Why using a phanref if there was not a finalize?
Why not simply testing the strong reference for null and doing the pre-morten actions?
Is it the conclusion that phanref have only sense with a finalize?
Now I am commenting the first part of the program.
This is how I think a WeakReference (weakref from now) object is meant to be used:
Either the program should check periodically (or before use of the referent object) the get method, or the poll method if the weakref was enqueued. The get method returns null if the g.c. encountered a weakref pointing to an object that is not strong, or softly reachable; because the g.c. calls clear on the weakref. If this weakref was associated with a ReferenceQueue at the time of creation, the g.c. when encouters the weakref calls its enqueue method marking that the referent object has left the weakly reachable state to pass to the state in which can be finalized. Note that a weakref object is enqueued by the g.c. to mark that has ended is weakly reachable state, but a phanref object is enqueued marking the beginning of the state as a phantomly reachable object.
In this way behaves the program. The g.c. releases the memory of the entries in the WeakHashMap whose keys are not stronlgy referenced in the program. Because this kind of Map holds its keys via weakref.
Hello ga11
I have written an example that I think shows the calls of the gc to enqueue() and clear(), and how Reference objects are intended to be used.
For the theory on these kind of objects please read the book Inside the Java 2 Virtual Machine by Bill Venners. The reading of the API is as well compulsary.
<html><body><code>
import java.lang.ref.*;
class VeryBig {
String ident;
public VeryBig(String id) { ident = id; }
public String toString() { return ident; }
public void finalize() { System.out.println("Finalizing " + ident); }
}
public class References2 {
static ReferenceQueue rq= new ReferenceQueue();
public static void checkQueue() {
Object inq = rq.poll();
while(inq != null) {
System.out.println("inq :" + inq + "\t" + "In queue: " +
(VeryBig)((Reference)inq).get());
inq = rq.poll();
}
}
public static void checkTheReferent(Reference[] ref) {
for(int i=0; i< ref.length; i++)
System.out.println(ref.get());
}
public static void main(String[] args) {
int size = 10;
// Or, choose size via the command line:
if(args.length > 0) size = Integer.parseInt(args[0]);
SoftReference[] sa = new SoftReference[size];
for(int i = 0; i < sa.length; i++) {
sa = new SoftReference(new VeryBig("Soft " + i), rq);
System.out.println("Just created: " + (VeryBig)sa.get());
}
WeakReference[] wa = new WeakReference[size];
for(int i = 0; i < wa.length; i++) {
wa = new WeakReference(new VeryBig("Weak " + i), rq);
System.out.println("Just created: " + (VeryBig)wa.get());
}
PhantomReference[] pa = new PhantomReference[size];
for(int i = 0; i < pa.length; i++) {
pa = new PhantomReference(new VeryBig("Phantom " + i), rq);
System.out.println("Just created: " + (VeryBig)pa.get()) ;
}
System.out.println("check 1");
checkQueue();
checkTheReferent(sa);
checkTheReferent(wa);
//use the soft and weak objects via get()...
System.out.println("Calling gc 1");
System.gc();
System.out.println("check 2");
checkQueue();
checkTheReferent(sa);
checkTheReferent(wa);
//...oops get() return null so they were collected so
//recreate them if you still need them
System.out.println("Calling gc 2");
System.gc();
System.out.println("checking 3");
checkQueue();
//poll() returns the phantom references so
//perform finalization needs and when it is done call
//clear like the following:
for(int i = 0; i < pa.length; i++) pa.clear();
}
} ///:~
</code></body></html>
The output when called with an argument of 2 is :
Just created: Soft 0
Just created: Soft 1
Just created: Weak 0
Just created: Weak 1
Just created: null
Just created: null
//Calling get() on a PhantomReference always returned null
// because the referent of a Phantom object can not be resurrected
//However the Phantom objects were created, just, we can not pritn
//them like that
check 1
//the checkQueue method didn't print anything because System.gc()
//was not called yet
Soft 0
Soft 1
Weak 0
Weak 1
//the checkTheReferent method is still able to access the referent
//objects via get()
Calling gc 1
Finalizing Soft 0
Finalizing Soft 1
Finalizing Weak 0
Finalizing Weak 1
Finalizing Phantom 0
Finalizing Phantom 1
//The Referent objects don't prevent the gc from finalizing the
//referent objects
//At this time the gc has called enque() and clear() on all the Soft
//and Weak reference object found, marking in this way that they
//has left the weak or soft "reachability state", and that they can
//be finalized. -As the output shows-
check 2
inq :java.lang.ref.SoftReference@720eeb In queue: null
inq :java.lang.ref.SoftReference@3179c3 In queue: null
inq :java.lang.ref.WeakReference@310d42 In queue: null
inq :java.lang.ref.WeakReference@5d87b2 In queue: null
//As the soft and weak objects has been enqueued and cleared the
//method checkQue has returned the reference objects that were
//enqueued but, their references were cleared. That it is indicated
// by the endings nulls.
null
null
null
null
//Again, as the soft and weak objects were cleared get() returns null.
//This is how soft and weak objects are intended to be used:
//between the point in which they are declared and the point in which
//the gc runs because of memory shortage. As the check 1 shows,
//during this period get() returns a usable object.
Calling gc 2
checking 3
inq :java.lang.ref.PhantomReference@77d134In queue: null
inq :java.lang.ref.PhantomReference@47e553In queue: null
//At last, what happened to the phantom objects?
//Well, a phantom object don't get enqued by the gc if it hasn't been
//finalized before. This code shows that. So a phantom object
//should be used consulting via poll() if it was enqued, by this
//time it has alredy been finalized; the program can now perform
//finalization actions in a safe way because it can not use the
//referent object. -get() return null-
//Once the program has finished these action it must permit the
//clearance of the memory of the referent objects by calling clear().
*/
http://forum.java.sun.com/faq.jsp#messageformat explains that. (And although it doesn't actually say so, using "i" as an array index in posted code is a bad idea because it disappears and causes the rest of your post to show up in italics. This is unfortunate because that's been the standard name for array indices since before I started programming in 1968.)
Some minor comments:
I can now see that the idea of calling enqueue() directly is not a very good one. This should be done by the g.c.
We have not to worry about the phantom references that don't have a finalize method, they are just enqueued by the first call to the g.c. , and they will be checked with poll(), as the ones that have a finalize method.