javagarbage-collectionfinalizefinalization

Prevent object garbage collection before other objects


I have a weakly-referenced array of weak references to further objects like so:

public class Foo{
    WeakReference<WeakReference<Bar>[]> cache;
}
public class Bar{
    private final WeakReference<Bar>[] ownerCache;
}

The array itself is weakly referred for reasons I will not go into right now. I want to make sure it is not garbage collected before ANY of the Bar objects reachable from it. In other words, it must exist in memory as long as any Bar object exists that can be reached from it. Then, if no Bar objects exist any more, I am better off if the array is also garbage collected. (Bar objects may or may not be strongly reachable from elsewhere.) I did this by referring to the cache array in a field inside all Bar objects. If the field is sufficient in making the array strongly reachable, it is not garbage collected. However, my code never actually uses that field and I can not make it public. (I get the "unused" warning on it.) I am afraid that the existence of such field is terminated either during compile time or run time, or it could get special treatment from the garbage collector that I am unaware of.

Is this the right solution? Does this solution achieve what I want regardless of the garbage collector or JVM implementation? If not, what would be a better method?


Solution

  • Here are a couple of ideas.

    If you control the Bar class, and each instance is referenced by no more than one array, you could add a reference from a Bar instance to the array. Reachable Bar instances will prevent the array from being collected.

    Alternatively, you could:

    1. Construct a reference queue for weak references to Bar instances.

      ReferenceQueue<Bar> m_refQueue = new ReferenceQueue<>();
      
    2. Construct each WeakReference with a reference to that queue.

      new WeakReference<Bar>( myBar, m_refQueue );
      
    3. Periodically poll that queue for available collectable instances, and remove them from your collection.

    4. You could make the collection itself a resizable data structure, avoiding the need to collect it.

      public class Foo {
         final @Nonnull List<WeakReference<Bar>> cache = new ArrayList<>();
      
         // Or you could use an IdentityHashSet from a third-party library.
      }
      

    EDIT

    As suggested by @Holger below, if an ordered list of references is not needed, your collection of WeakReference can be a java.util.WeakHashMap, used as a set. The keys are weak references; the values can be null. The map is a resizable data structure, so you can simply hold an ordinary reference to the map.

        public class Foo {
           final @Nonnull WeakHashMap<WeakReference<Bar>,Object> cache
              = new WeakHashMap<>();