status of gcj's boehm collector?
Boehm, Hans
hans_boehm@hp.com
Tue Dec 4 17:06:00 GMT 2001
> From: Adam Megacz [mailto:gcj@lists.megacz.com]
> "Boehm, Hans" <hans_boehm@hp.com> writes:
> > The collector does provide for incremental and generational
> collection, and
> > has for a long time. Gcj currently doesn't support that
> functionality.
>
> "that functionality" == incremental, or "that functionality"
> == generational,
> or both?
Both. They're currently coupled in that they both use the same mechanism
and in that GC_enable_incremental() will turn both on. If you set the
target pause time (TIME_LIMIT) to a large value, you will essentially get
just generational GC, which might give you better throughput than turning
them both on. (I just now introduced GC_time_limit, so that this won't
require a recompilation in the future.)
I suspect that doing full incremental collections every time is nearly
always a losing proposition, and hence not very interesting.
>
> > 1) It can only identify modified pages, not individual
> objects. And new
> > objects often reside on the same page as old objects. This
> means that it
> > spends appreciably more time scanning potentially old and
> modified objects
> > than a copying generational collector. The net effect
> generally seems to be
> > that it's a performance (throughput) win only for a
> minority of programs, or
> > if your program pages. (In the latter case buying more
> memory is probably a
> > better solution these days.) It does improve pause times.
>
> This seems to be a reason why an incremental collector with page-level
> granularity would have lower throughput than a generational
> collector. Am I correct?
This isn't an incremental versus generational issue. They both need a write
barrier, i.e. some way to determine what has been modified. Smaller
granularity than page size is usually better for the write barrier. But
there are tradeoffs. If the granularity is too small, just looking for
modified regions can get expensive. Using the VM system as a write-barrier
has the significant advantage that you don't slow down long-running but
non-allocating code.
>
>
> > 2) On a platform like Linux modified page information is
> kept by write
> > protecting pages and catching write faults. This works
> fine if the page is
> > modified as the result of an instruction executed by the
> user program. It
> > causes problems if the write occurs as the result of a
> system call. Thus
> > system calls must be suitably protected. There are some
> hooks in the GC
> > library to do this, but libgcj doesn't. Furthermore, those
> hooks currently
> > have problems in multithreaded environments with blocking
> system calls.
> > (This situation is probably somewhat better on Solaris,
> since there is a way
> > to retrieve dirty bits through /proc. We have vague plans
> to see if we can
> > do this faster in Linux/IA64, but that's not going to happen soon.)
>
> Okay, so this means that incremental GC isn't likely to happen. I
> think I can live with that. How about generational GC?
>
Same issue. Generational collectors need a write barrier to track writes to
old objects. That currently involves catching write faults on Linux. And
those write faults can still happen in system calls.
I know of two ways out of this:
1) Use a software write barrier. Insert instructions to keep track of heap
writes. This is what JVMs with generational collectors generally do. It's
not free. It would be hard to do in gcj because the C++ code would have to
play by the rules.
2) Add dirty bit support to the kernel. So far this has been a tough sell,
in part because I don't actually get that many complaints about pause times.
(I think Solaris added this for other reasons, perhaps checkpointing. But
that argument doesn't seem to have convinced too many OS implementors
either.) It looks like on IA64 the cost might be so little that we can
justify it.
Hans
More information about the Java
mailing list