On Mon, Aug 15, 2005 at 12:40:05 +0100, Adrian Howard wrote: > On 15 Aug 2005, at 02:13, David Formosa ((aka ? the Platypus)) wrote: > > >After a very fruitful discussion I've rewritten my suggested GC API. > >Comments please. > [snip] > > I'm speaking from complete ignorance since I've only been vaguely following > the subject... but four additional things that strike me as useful (because > I found them so in > Pop-11 when I used it) would be: > > 1) Some way of declaring objects as being "fixed" so we can pass them to > external code without having to worry about the GC moving them around.
A handle to an object should always be fixed, I would think... Even under a copying mechanism, you can have an arena for handles, and an arena for the actual data which is actually collected, and points back to the data. Optimized access (auto unboxing, various inferrencing by the compiler) could be made such that it doesn't go through the handle unless absolutely necessary. > 2) Some way of being able to tell the garbage collector to ignore the > current contents of the heap for the purposes of GC. One Pop-11 idiom was to > do something like: > > ;;; create a whole bunch of complicated self referencing > ;;; objects that we know are going to persist over time > > sys_garbage(); ;;; run the garbage collector > sys_lock_heap(); ;;; lock stuff currently in the heap > > ;;; do lots of stuff that now runs quicker since the GC doesn't > ;;; have to worry about marking the objects that we know are > ;;; not going away > > sys_unlock_heap(); ;;; give the GC full rein again We are trying to design a requirement based interface, so that the GC can be changed, but behavior remains consistent. This should be more like do :GC::priority(:low) { # anything that isn't GC::timely or possibly affecting # something that is GC::timely is not cleaned up till # later } do :GC::nodelay { # the GC can work, but timeliness and throughput are # ignored for the sake of performance of "real" code # this means that most GCs are disabled, but a # background thread GC will just have it's priority # lowered # implies that 'timely' now means 'at some point' } do :GC::nodestroy { # the GC is told to completely freeze the state of # things, delaying all work until after the block exits # this means that you can rely on GC::timely objects # being alive even when they shouldn't be. # this is orthogonal to GC::nodelay - under plain # GC::disabled objects may be collected for overall # performance reasons, and then simply put on the # finalize queue for finalization on block exit. # applying both nodelay and nodestroy causes the GC # system to completely turn off, so that objects are # neither finalized nor collected. } do :GC::disabled { # nodelay and nodestroy together } do :GC::priority(:high) { # work very hard to conserve memory } do :GC::critical { # it's like GC::timely for everything } Possibly with e.g. $*RUNTIME.Memory.GarbageCollector.disable thrown in for flexibility. Block scoped behavior has some advantages: Exceptions raised from the block will cause augmented behavior to be reverted on scope exit Structure is clearer But it's not as capable, since behavior cannot be changed to affect calling scopes. This is important, but should be discouraged from normal use. > 3) Some way of marking structures/fields so their reference doesn't count. > Weakrefs basically. Yes... i think this is a container trait. Anybody got an opinion? my $var is weakref = $object; > 4) Hooks to run code before/after GC. Occasionally very useful. (e.g. with > the gc hooks and heap locking/unlocking you could implement your own > ephemeral GC system in Pop-11). This is possibly done by introspecting $*RUNTIME.Memory.GarbageCollector, and seeing if it supports events. What if it's a thread continuously running in the background, which is only synched when something GC::timely may be involved? This is getting me thinking though: $*RUNTIME.Memory.GarbageCollector.dispose($object); # force it, # even if it should be alive $*RUNTIME.Memory.GarbageCollector.clean($object); # check it These two are non recursive by default, and they accept the ':recursive(1)' optional param to imply that referred subobjects should be applied too. They should also allow very tight loops to be controlled under do :GC::disabled, without wasting lots of memory. On block exit a consistent state is reached - any timely objects that should have been destroyed in the nested block will be finalized. Hmmm... ;-) sub nothingness () { $*RUNTIME.Memory.GarbageCollector.dispose($*RUNTIME, :recursive(1)); } -- () Yuval Kogman <[EMAIL PROTECTED]> 0xEBD27418 perl hacker & /\ kung foo master: /me sneaks up from another MIME part: neeyah!!!!!