How unsafe are unsafeThawArray# and unsafeFreezeArray#

Simon Marlow marlowsd at gmail.com
Fri Mar 9 13:26:34 CET 2012


On 09/03/2012 11:44, John Meacham wrote:
> Out of curiosity, Is the reason you keep track of mutable vs not
> mutable heap allocations in order to optimize the generational garbage
> collector? as in, if a non-mutable value is placed in an older
> generation you don't need to worry about it being updated with a link
> to a newer one or is there another reason you keep track of it? Is it
> a pure optimization or needed for correctness?

It's for correctness - this is how we track all the pointers from the 
old generation to the new generation.

There are lots of different ways of doing generational GC write 
barriers, and indeeed GHC uses a mixture of different methods: a 
remembered set for updated thunks and mutated IORefs, and a card table 
for arrays.  Mutable arrays normally stay in the remembered set 
continuously, so that the write barrier for array mutation doesn't have 
to worry about adding the array to the remembered set, but it does 
modify the card table.  An immutable array can be dropped from the 
remembered set, but only once all its pointers are safely pointing to 
the old generation.  But then, unsafeThawArray has to put it back in the 
remembered set again.

Once upon a time all the mutable objects were in the remembered set, but 
gradually we've been moving away from this and adding them to the 
remembered set only when they get modified.  There are a few objects 
that still use the old method: TVars, for example.

> A weakness of jhc right now is its stop the world garbage collector,
> so far, I have been mitigating it by not creating garbage whenever
> possible, I do an escape analysis and allocate values on the stack
> when possible, and recognize linear uses of heap value in some
> circumstances and re-use heap locations directly (like when a cons
> cell is deconstructed and another is constructed right away I can
> reuse the spacue in certain cases) but eventually a full GC needs to
> run and it blocks the whole runtime which is particularly not good for
> embedded targets (where jhc seems to be thriving at the moment.). My
> unsafeFreeze and unsafeThaw are currently NOPs. frozen arrays are just
> a newtype of non-frozen ones (see
> http://repetae.net/dw/darcsweb.cgi?r=jhc;a=headblob;f=/lib/jhc-prim/Jhc/Prim/Array.hs)

Interesting - we do generational GC instead of escape analysis and other 
"compile-time GC" techniques.  IMO, generational GC is a necessity, and 
once you have it, you don't need to worry so much about short-lived 
allocation because it all gets recycled in the cache.  (try +RTS -G1 
sometime to see the difference between generational GC and ordinary 
2-space copying).

On the other hand, generational GC does give rise to some strange 
performance characteristics, especially with mutable objects and 
sometimes laziness.  And it doesn't solve the pause time problem, except 
that the long pauses are less frequent.  Improving pause times is high 
up my list of things we want to do in the GC.

Cheers,
	Simon



More information about the Glasgow-haskell-users mailing list