I have read that in Java, GC (Garbage Collection) will clean up objects that are not referenced in the Heap memory.
I am not sure how to test or not sure if, after line 3, the variables person, room (in the voidTest function) can be called as having no reference.
Does anyone know how to test or could explain further for me?
Thank you!
class Main{
public static void main(String[] args) {
voidTest();
// is Gc clean room and person variable in void Test ?
}
public static void voidTest(){
Person person = new Person();
Room room = new Room();
room.person = person;
person.room = room;
}
}
class Room{
public int id;
public Person person;
}
class Person{
public String name;
public Room roon;
}
EDIT: It turns out that this question is actually about circular references, which I blanked on because obviously circular references are removed (which is only obvious if you've been programming in Java for 15 years). Here's a link to the SO question that the OP found useful: How does Java Garbage Collection work with Circular References?
Finalizers aren't a great idea and they are being removed from the language. But they are still available, so that allows you to do some cheap and easy GC testing. Calling System.gc()
manually allows you to see the result of a garbage collection.
public class GCTesting {
public static void main( String[] args ) {
test();
System.gc();
}
private static void test() {
new GCTesting();
}
@Override
protected void finalize() {
System.out.println( "Bye!" );
}
}
Since finalize()
is being removed I updated my program to give a quick example how to do this with a PhantomReference
. In my testing, I had to call remove()
instead of poll()
because it seems to take a bit of time for the referent to be enqueued, poll()
would always return null
immediately after a call to System.gc()
. In more normal code, I'd assume poll()
would be the better choice. I'm calling remove(1000)
just because I want the test to end after a brief wait. Also, saving the PhantomRefence
is important, otherwise it will also be garbage collected (and never enqueued).
public class GCTesting {
public static void main( String[] args ) throws Exception {
finalizers.add( new Finalizer( new GCTesting(), collected ) );
System.gc();
for( Reference<?> f; (f = collected.remove(1000)) != null; )
System.out.println( "collected " + f );
}
static ReferenceQueue<GCTesting> collected = new ReferenceQueue<>();
static ArrayList<Finalizer> finalizers = new ArrayList<>();
static class Finalizer extends PhantomReference<GCTesting> {
public Finalizer( GCTesting gct, ReferenceQueue<GCTesting> q ) {
super( gct, q );
}
}
}