Question

I read that the JVM gc, after finding an unreachable Object, runs the finalize() method of that object. Then it checks if the object is still unreachable, and gets rid of it if it is not. So i wrote a finalize that would make it's object's reference available again:

public class Stuff {

 List<Object> list;

 public Stuff(List<Object> list) {
  this.list = list;
 }

 @Override
 protected void finalize() throws Throwable {
  list.add(this);
  System.out.println("A Stuff is finalized");
 }
}

Here's the main method:

public class Main { 
 public static void main(String[] args) {
  List<Object> list = new ArrayList<>();
  list.add(new Stuff(list));
  list.remove(0);
  System.gc();
  System.out.println(list.get(0));
 }
}

The gc is run, since "A stuff is finalized" apperas on the standard output, but the printline in main afterwards throws an IndexOutOfBoundsException. Can i make this work at all?

I don't usually use finalize at all, I just thought it would be interesting to see if finalize can make its object's reference available again. Can i make this work?

Was it helpful?

Solution

Finalizers run in a dedicated finalizer thread and what you have written is thread-unsafe code. Use a synchronized collection, for example.

The other pitfall is, just calling System.gc() is no guarantee that the finalizer has run by the time that method call returns. The finalizer has merely been enqueued in the finalizer thread's queue—if even that. To work around this you should really use a synchronization helper such as CountDownLatch and call System.gc() two or three times, for good measure.

Here, your code improved with the above ideas:

public class Stuff {

  static final List<Stuff> list = Collections.synchronizedList(new ArrayList<Stuff>());
  static final CountDownLatch cdl = new CountDownLatch(1);

  @Override protected void finalize() {
    list.add(this);
    cdl.countDown();
  }

  public static void main(String[] args) throws Exception {
    list.add(new Stuff());
    list.remove(0);
    System.gc();
    System.gc();
    cdl.await();
    System.out.println(list.size());
  }
}

OTHER TIPS

List<Object> list = new ArrayList<>();
  list.add(new Stuff(list));
  list.remove(0);
  System.gc();
  System.out.println(list.get(0));

You are creating list of Object's not List of instances of Stuff class with implemented finalize. So ArrayIndexOutOfBound is expected.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top