Re: Controlling the Garbage Collector
On Tuesday, June 26, 2012 2:25:53 PM UTC+2, Andreas Leitgeb wrote:
Robert Klemme <shortcutter@googlemail.com> wrote:
Thank you for the elaboration, Eric and Andreas! I think a non uniform=
object memory model (e.g. some GCed, some manually managed) cannot get=
rid of the GC overhead even for the manual kind as long as it is allowe=
d
to have references between the different kinds of objects.
It is no problem for GC'ed objects to be referenced from manually
managed objects.
I think it is. The point in separating object kinds is to reduce the numbe=
r of objects GC has to look at in order to avoid looking at long lived old =
objects over and over again. But to determine the liveliness state of an "=
automatic" object GC would still have to look at the "manual" object _durin=
g each allocation_. Even worse, since references only point forward (other=
wise we'd have introduced a tremendous memory - and probably CPU - hit for =
bidirectional references) it is necessary to look at _all_ "manual" objects=
reachable from roots.
In the reverse case, it could mean that references to manually
collected items could become "stale". Of course that would have
to be a fundamentally different kind of "stale" as what we know
from C.
Imagine there was a class ManualReference, similar to WeakReference.
When a manually managed object was created, it would be transparently
wrapped by such a ManualReference. Any ref to such an object would
really be to a ManualReference that in turn holds the object, and
certain things done on the reference are passed to it's payload, like
accessing fields, or calling methods. Other stuff (assignment, or
passing around the value) would still be a local access on the variable
itself. That would surely need some changes in the JVM and/or the
compiler to work.
(I'm not proposing that. I just find it challenging to think it through.)
Now, if by some new mechanism (e.g. a new keyword "free"), a manually
managed object was freed, then the (transparent) ManualReference would
be simply cleared, and all further accesses cause a NullPointerException.
The ManualReference object itself would be normally GC-managed, thus
remain in memory at least until all references to it are indeed cleared.
You replaced the automatic collected object by another automatic collected =
object (the ManualReference). Again, nothing gained in terms of number of =
objects to look at for the GC.
More abstract: you introduced a reference type which can be set to null at =
any time (i.e. when someone decides to "free" this object). Basically that=
's the same situation we have with WeakReference now and as consequence you=
need to check the reference for null on every access.
Because of concurrency you need to be able to lock the reference for a cert=
ain duration (e.g. a method call) in order to avoid clearing during a logic=
al operation. You would at least need to be able to to some atomic "check =
for null and use ref" otherwise the null check would be moot. With WeakRef=
erence you do that by copying the reference to an ordinary reference. The =
clearing mechanism would need to prevent clearing while the reference is lo=
cked / copied into a regular reference. As a consequence the effect of you=
r "free" operation is not to actually remove the object but only to _schedu=
le_ it for removal. This is a quite similar situation to "automatic" objec=
ts which have all references to them cleared (or GC'ed themselves) btw. Si=
nce we cannot impose a limit on the locking time and the actual time lag be=
tween "free" and last "unlock" can be quite high, we might not have gained =
much in term of control of memory usage.
Even worse, someone else might come along and do a "lock" after "free" thus=
prolonging the locking period. The alternative would be to disallow "lock=
" after free but that comes with issues of it's own: then any "lock" operat=
ion could fail and the user of the language is prompted with the issue that=
he needs to deal with the exception originating from a failed lock. Maybe=
that could be salvaged by making all "lock" operations after "free" return=
null. That would be similar to WeakReference.
"locking" of course would need to be reentrant so several methods of a clas=
s could cooperate and use the same "manual" member object. That means: a "=
lock" after "free" must return null only if it is the first "lock" of a thr=
ead, i.e. if the thread did not have the lock before. As another side effe=
ct we will have a situation where after a "free" some threads might still s=
ee an instance while others don't. Well, that can happen with WeakReferenc=
e as well depending on when threads fetch the reference, so that might not =
be too big an issue.
Now you would have to check the refcount of the "manual" object on every "u=
nlock". This has a number of consequences
- refcount checking might be imposed on the thread which uses a "manual" o=
bject creating CPU overhead
- additional synchronization is necessary to avoid race conditions for "lo=
ck" and "unlock"
- refcount checking does not work with circular references
Gist: I think it *could* be done, but it would surely require some
deep changes in Java, that are not justified by any so far identified
advantage.
I don't even think there is an advantage. The - admittedly brief - analysi=
s above shows that there is a ton of issues lurking and I believe allowing =
mixed references between "manual" and "automatic" objects introduces more c=
omplexity (in terms of code, runtime and probably also memory) instead of r=
elieving us from the old object overhead.
Kind regards
robert