Etienne Gagnon wrote:
I was making it more complex than it needs...
Here's an improvement...
1- During normal operation, the VM keeps hard references to all class
loader instances. [This prevents any premature class loader death].
2- At the start of an epoch (or just before), all vtable bits (or byte
or word) are cleared. [From now on, I will use the "bit" terminology for
simplicity. The bit may reside in an otherwise unused byte or even
word, for efficiency purpose].
3- The end of an epoch happens "no sooner" than when all generations /
heap parts have been collected at least once since the epoch start.
[One can cheat and visit objects of uncollected parts/generations to
mark their vtables].
4- An "old generation" collection is chosen as the end of an epoch.
This is "end of epoch collection". [As class loaders/classes are likely
to have moved to older generations, there's no point trying to kill them
in young collections].
In fact classes and clasloaders would be perfect targets for pretenuring.
5- Just before starting the "end of epoch collection", all the
class-loader vtable lists are visited (and bits are cleared in prevision
of the next epoch). All vm references to [candidate] class loaders with
no surviving objects (nor active methods) (e.g. no vtable bit set) are
made "weak".
6- The "end of epoch collection" is launched.
7- There's actually no need for "rescuing" class loaders. The vm
reference to any surviving [candidate] class loader is made hard again.
Interesting fact: other candidate class loaders cannot have any
instance (nor any active method) as GC doesn't create instances nor
method calls. So, there's no need for a rescuing dance! The list of
dying class loaders can be used for freeing related native resources.
IMO: simple, clean, efficient...
It has the downside of being inherently 'stop the world', though. I
don't see this as being a big disadvantage, because it shouldn't be hard
(compared to the work of building a concurrent collector in the first
place) to extend to a concurrent class-unloader.
Etienne
Etienne Gagnon wrote:
If it does, then can somebody explain to me what's wrong with
my proposal of setting, in normal operation, a "hard" reference to
class loader objects, and then temporarily using weak, rescuable
reference to enable class loader collection? I don't see a performance
hog there. Rescuing a few class loaders (if any) and their related
classes once per epoch shouldn't cost much! I have yet to see a
convincing explanation of how continuous collection of "object-vtables"
would be more efficient...
Really, even with Robin's proposal, this would work. If a class loader
gets into an unloadable state, then most likely, the class loader and
all classes it has loaded will have migrated to an old generation. So,
as long as we set then end of a class unloading epoch at an old
generation collection, then we can simply "weaken" the class loader
reference during collection (only when the bit of all related vtables
are unset), then apply the finalization-like rescue dance to class
loaders.
[*]This wouldn't affect any other operation, during other GC cycles, as
Robin's unconditional bit/byte/word vtable write only serves to tell us
whether a class loader has had living instances of its classes during
the epoch.
--
Robin Garner
Dept. of Computer Science
Australian National University