3

In C++ I use reference counted objects to impplement a for of "auto" recycling object pool

SmartPointer<ObjType> object = pool.getObject(); // hold reference

// ... do stuff with object over time.

object = nullptr; // that is when reference 
                  // count goes to 0

-- Now I have on the C++ objects an "onFinalRelease()" method which gets called when the refcount reaches 0. I can overide this ( default is delete(this) ) to auto-recycle objects rather than destroying them.

The question is can I implement this pattern with some combination of java reference types and reference pools. Of course this is for a type of large complex expensive to create object where it makes sense. That is I want to do:

SomeReference r = referenceQueue.getReference();

pool.recycle(r.takeBackUnusedObjectFromGC()); // ??????????????????????????

This would be real nice :)

peterk
  • 5,136
  • 6
  • 33
  • 47
  • The problem with using the GC is you don't know when it will be run, if ever. This can mean you run out of resources waiting for the GC to recycle the objects. You are better off with explicit recycling or pre-allocating the objects e.g. ThreadLocal, and re-using them. – Peter Lawrey Jan 09 '12 at 20:26

4 Answers4

7

You can use PhantomReferences to do something like this. Have an interface (proxy) object with a (strong, unidirectional) reference to the expensive object. Also keep a strong reference to the expensive object in your pool management. Keep a PhantomReference to the interface object. Once the PhantomReference comes up on its ReferenceQueue you know for sure that the expensive object is not being used through an interface object (even allowing for finalisation). The expensive object can now be reused with a new interface object.

However, it probably isn't worth it.

Gray
  • 115,027
  • 24
  • 293
  • 354
Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • Very interesting. Why do you use the interface (proxy) object instead of just making the pool management use `PhantomReference`s ? – Mike Nakis Jan 09 '12 at 20:26
  • `PhantomReference.get` always returns `null`. Even `WeakReference.get` isn't that great. – Tom Hawtin - tackline Jan 09 '12 at 20:31
  • Ah - I see :) cool all *sub* objects to the interface are still valid when the proxy is determined to be unreachable even it it is scheduled to be destroyed so removing it's pieces is fine. Good as my expensive object has a couple of large parts. would be nice for java really to support this pattern completely but this trick will work Thanks. – peterk Jan 10 '12 at 12:07
  • @peterk I believe it is quite expensive in terms of GC activity. So not so good for, say, memory pooling. – Tom Hawtin - tackline Jan 10 '12 at 12:35
  • I wonder - I'll have to test it. If one sets the pointer to the internal part to null maybe the GC will then ingore the whole subtree? – peterk Jan 10 '12 at 22:04
  • Just found another good use for this, and that is in a graphics texture cache which can be expensive to load. – peterk Jul 04 '12 at 09:19
  • Is there a way to use this to perform `View` recycling in an Android `Adapter`? – Andrew Wyld Apr 29 '13 at 15:21
1

With reference counting, there is a clearly defined time when an object becomes garbage - when the reference count goes to zero. With Java's garbage collection, there is no guarantee that a given object will ever be garbage collected, even if there are no more strong references to it.

Implementing your own reference counter by hand is the best solution I can think of.

Russell Zahniser
  • 16,188
  • 39
  • 30
  • quite true, but it wouldn't get garbage collected whether I reuse it or not so either way the same amount of memory is consumed. But the object setup and destruction time would be saved. – peterk Jan 10 '12 at 11:58
  • BTW - I agree that using an explicit release is more efficient. If cities were designed the java way, everyone would throw all their trash on the street all the time clogging up traffic, and traffic would have to stop every time a cleaner went through. Best to have most collection explicit, and have low priority GC to pick up inevitable accidental litter. – peterk Jan 10 '12 at 12:10
  • also - as java has no support for syntyactical sugar that can create smart poinnters - ie: overloading operator= for assignment or overloading operator'.' somehow, nor does it have syntactical support for "stack scoped" 'destruction' that happens, even when a method is exited, it's not practical to write if frequent and you still end up with stuff having to be collected. – peterk Jan 10 '12 at 12:21
0

This class may be what you're looking for:

https://commons.apache.org/proper/commons-pool/apidocs/org/apache/commons/pool2/impl/SoftReferenceObjectPool.html

Pr0methean
  • 303
  • 4
  • 14
0

Java has something similar called the finalize method. Unfortunately, once it runs for an object, there's no going back. In addition, it's not even guaranteed to run.

You best bet might be to create a pool of objects and track yourself whether they can be reused or not. Apache Commons Pool might be useful for this.

Edward Dale
  • 29,597
  • 13
  • 90
  • 129
  • Not exactly. The `finalize()` method is run no more than once for an object, but it can "resurrect" the object, making it not GC-able. This is one of the big reasons that using the `finalize()` method is not recommended. – erickson Jan 09 '12 at 20:16
  • The problem with finalize() is that when it happens, objects referenced from within the object being finalized may not exist anymore. Things look really scary from within finalize(); the cluster of objects to which the current object belongs has already been decomposed, most of the other objects have been sent to oblivion, and now it is the current object's turn. Really, the only thing you can do is invoke some native method to release some native handle and nothing else. – Mike Nakis Jan 09 '12 at 20:17
  • @erickson: Resurrection occurred to me as well, but it only works once - when that object becomes garbage again, it has already been finalized and so it is collected immediately without the finalizer being called. For a pool where objects would be reused multiple times it won't work. – Russell Zahniser Jan 09 '12 at 20:48