Because I'd want the VM to *guarantee* that the dispose() method would
be called *as* *soon* *as* the count reaches 0. This is in contrast to
WeakReferences that may never have their referrents be reclaimed.
Right. But if the objects that are holding your CountedReferences are
themselves managed by the GC, then they'll only decrement their counts
when they get collected, so you're still dependent on the GC to make your
refcounted objects die.
Of course, you could manage your reference-holding objects by refcounting.
But here, obviously, you have an infinite regress: for this to work, you
have to use refcounting all the way back to the root set, ie replace GC
with refcounting altogether. And even then, you're stuffed if you hit
cyclic garbage: you can only free that when the cycle detector runs, which
happens periodically, like GC. Unless you're going to cycle-detect every
time you decrement a pointer, which is going to have some performance
penalties, to put it mildly. On top of the fact that large-scale
refcounting is incredibly slow anyway, because of all the writes to
memory.
Now, having said that, the fragrant David Bacon has come up with an edgy
modern style of refcounting which does actually deliver pretty good
performance:
http://www.research.ibm.com/people/d/dfb/recycler-publications.html
It deals with cyclic garbage, runs only 5-10% slower than a proper GC,
and has really good realtime properties. However, one of the tradeoffs it
makes to achieve this is deferring decrements, which means it doesn't
quite have the properties you want.
That's just it: for my use case, I *can't* do it explicitly because I
have no way of knowing if my resource is either currently in use or will
be used again in the not-too-distant future (because some code/object
somewhere still has a hard reference to it).
For the record, the use-case is as follows. I have some class
(ImageInfo) that reads image files (possibly very large image files).
As part of the class's implementation, it opens a RandomAccessFile on
the image and reads "chunks" of the file into memory. (The "chunks"
themselves are held by SoftReferences -- a SoftChunkyByteBuffer -- and
this part works fine.)
The class has many methods, each of which accesses different parts of
the image, e.g., get the image's metadata (getMetadata()), the image's
color profile (getColorProfile()), the image's thumbnail
(getThumbnail()), and the image itself (getImage()). All said methods
must ultimately read data from the "chunks."
For a given image file F, a new ImageInfo(F) is created. Once created,
the rest of the code will use the various methods of ImageInfo in an
arbitrary order. The first method called (regardless of which method it
is) creates the SoftChunkyByteBuffer and, after creation, it (and the
RandomAccessFile it uses) sticks around.
After the first method is called, I can't just close the
RandomAccessFile because it might be the case that another method is
about to be called for the same image F via the same ImageInfo object.
In fact, I can *never* explicitly close the RandomAccessFile because of
this.
This is indeed a painful situation. But my point stands: since you're
dependent on GC of the reference-holding objects to the decrement the
count, you'd still lose with refcounting.
In C++, you could do this, because you implicitly or explicitly destroy
objects as soon as you're done with them - but there's nothing stopping
you doing this in java! Create an ImageInfoHandle class, through which you
use your ImageInfo. Give it a release() method. Call it whenever a
destructor would be called in C++ - when a locally-held instance goes out
of scope (using try-finally), or when you know you're done with a shared
instance (where you'd use delete in C++).
Or, do what Daniele suggested, and hide the details of the RAF being
opened and closed altogether.
tom