icbytes
icbytes

Reputation: 1851

Object pool pattern - separation of concerns - encapsulation: Who is responsible for deleting an instance?

Situation

During a development I implemented the design pattern called object-pool-pattern. Basically this means that our class has a static public method and a static-protected attribute. This attribute carries all instances, which can be retrieved by the static public method if a certain object key is provided. I use a method called get_instance to retrieve the instance into a local reference variable and then invoke other methods on it. In our case, a wrapping function module calls get_instance, and later on invokes some methods on that instance. In a particular case the lifetime of a certain instance ended. So, it has to be removed from the object pool. Until now I do it inside an instance-method, where the object deletes itself from the pool (a table).

Assumption

The outer reference in the function module should have become invalid, because it does reference a not existing object. The garbage collector should now carry about this orphaned reference, If I assume correctly. (In general this goes the other way around: A not referenced object is generally killed by the GC.) In this case I still assume that the local reference in my function module should also become collected. Because the object it was referring to, was deleted from the object-pool. Nevertheless, until now, I still call Free lr_myreference. A co-worker said, it might be better to implement a static public method, which would NOT act on the reference but simply killing the entry of the pool, prior to calling Free lr_myreference.

Questions

In general I am thinking about: Who is responsible for deleting the object from the pool? What about other local references referring to the entry in the table (the "original reference")?

Upvotes: 4

Views: 323

Answers (2)

vwegert
vwegert

Reputation: 18483

I use the very same pattern you described rather frequently, preferably with some hash table kept as a static attribute of a factory/manager/pool class.

Personally, I try to avoid objects that need to be finalized explicitly wherever possible. From my experience, as the application grows more complex, someone will always tend to forget the finalization. This in turn might lead to any number of undesirable side effects that are notoriously hard to debug. I try to follow the basic assumption that the garbage collector will know best when to remove an object, and that once the object is gone, that's all there is. As long as anyone (a function group, another class, doesn't matter) keeps a reference to an object, it is still in use and won't be gc'ed. Aside from the Control Framework, where you need to explicitly deconstruct object instances frequently, this approach works quite well.

The apparent downside of this approach is that the object pool will tend to grow unless implemented properly. My instance hash tables don't contain hard references to the instances; instead, I use CL_ABAP_WEAK_REFERENCE to keep track of the managed objects. This allows for the garbage collector to remove all managed instances that are not in use elsewhere. Of course, this also means that you need to track instances that you still need via other direct references (for example using a lock object that encapsulates the ENQUEUE/DEQUEUE calls and at the same time serves as a lock token - whoever is the current owner of that object is also responsible for releasing the lock again).

Caution: There's a fairly common structural mistake that has to be avoided when using weak references extensively. I've written an SCN article some time ago that contains a (counter)example. Bottom line: If a managing object (in your example, the pool class) is referenced via a weak reference, make sure that the managed instances have a hard reference to the manager - otherwise you might unexpectedly end up with several sets of managed instances that represent the same thing.

Upvotes: 4

Sam Holder
Sam Holder

Reputation: 32936

In essence you are temporarily transferring ownership of (or at least lending) the object from the pool to the caller of get_instance and so the pool cannot kill the object or remove it from the pool until it knows that the new owner has finished using the object. If it does then the current owner may be left with an invalid object.

So in order for the pool to do its job correctly you need to return the object to the pool (or tell it that you have finished using it) so the pool can know which objects are not currently in use and can destroy them safely.

I would have a return_instance object which would do this.

If you have multiple clients calling get_instance and you are giving them the same instance then you'll need to track by reference count, otherwise you can just keep the references in two lists, one for available objects and another for currently loaned out objects, and just switch between the lists when get_instance and return_instance are called.

The clients should not be responsible for destroying the objects, otherwise what's the point of having a pool? Just have a factory instead...

I asked a slightly related question a while ago, which influenced my thinking

Upvotes: 2

Related Questions