From facbc8bd56644ad5be1f38bd2bb124a47420672e Mon Sep 17 00:00:00 2001 From: Richard Kistruck Date: Fri, 1 Dec 2006 19:19:00 +0000 Subject: [PATCH] Mps wiki: gc story: what triggers a gc? Copied from Perforce Change: 161058 ServerID: perforce.ravenbrook.com --- mps/manual/wiki/gc_story.html | 101 ++++++++++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 4 deletions(-) diff --git a/mps/manual/wiki/gc_story.html b/mps/manual/wiki/gc_story.html index 29ab83c59d9..ac1d1045311 100644 --- a/mps/manual/wiki/gc_story.html +++ b/mps/manual/wiki/gc_story.html @@ -56,26 +56,118 @@

Concepts and Datastructures

+
+
Zone
+
Stripe of memory.
+
+

Set-up

-

Mutator creates an array of mps_gen_param_s structs (for example: [ { 100KB, 90% mortality }, { 100K, 50% mortality } ] ), passes it to mps_chain_create, and uses this chain to create a new AMC pool.

+

Say the mutator creates an array of 2 mps_gen_param_s structs:

+ -

The Chain contains an array of two GenDescs: numbers 0 and 1. The AMC pool creates *three* PoolGens: 0 and 1 are linked to the corresponding GenDesc, and 2 is linked to the arena-wide "topGen" GenDesc.

+

It passes this array to mps_chain_create, and then uses the chain to create a new AMC pool.

-

The GenDesc zonesets are empty. The PoolGen newSizes are zero.

+

The Chain contains an array of two GenDescs: numbers 0 and 1. The AMC pool creates *three* PoolGens:

+ + +

The PoolGen newSizes are zero. The GenDesc zonesets are empty.

Accumulating objects

+

Mutator creates and uses an allocation buffer, making new objects accumulate in the nursery generation.

-

Triggering a major collection

+

Placement

+ +

When AMCBufferFill asks for new memory segments, it passes the PoolGen's "nr" generation number (0 for mutator allocation, 1 or 2 for preserved objects) as a segment-placement preference (with SegPrefGen).

+ +

ArenaVM tries hard to keep all segments for this SegPrefGen-number together in the same zone or zones, and separate from the zones used for all other things. (Such as: zones with other generations, blacklist zones, and as-yet unused zones).

+ + +

How big, and where, is this generation?

+ +

AMCBufferFill does this accounting: + +

The segment's size is added into the PoolGen's newSize.

+ +

The segment's zoneset is unioned into the GenDesc zoneset (by calling PoolGenUpdateZones).

+ + +

Call paths that may trigger a collection

+ +

All collections start from ArenaStep(). There are two routes into ArenaStep: an explicit call to mps_arena_step(), or an implicit one from the time-stealing ArenaPolls in mps_alloc, mps_reserve, and mps_alloc_pattern_end/reset.

+ + +

Triggering a full collection

+ + +

Condition

+ +

There are two trigger conditions:

+ +

Firstly, lots of "spare time". An explicit call to mps_arena_step() can specify non-zero interval and multiplier. If (interval x multiplier) is big enough, and it's been long enough since the last one, start a full collection.

+ +

Secondly (when ArenaStep calls TracePoll) the infamous "dynamic criterion". The plan is to start a full collection soon enough so that we don't completely run out of memory. I hope that the idea of this is:

+ +
    +
  1. look ahead to how much extra forwarding-space would be required for a full collection;
  2. +
  3. add how much extra client-allocation would occur during collection;
  4. +
  5. and compare it against ArenaAvail.
  6. +
+ +

Both trigger conditions call traceStartCollectAll().

+ + +

What to condemn

+ +

traceStartCollectAll() finds all chains, all the PoolGens in Gen 0 of those chains, all the pools those PoolGens are part of, all the segments of those pools, and condemns all those segments:

+ +
traceStartCollectAll():
+  traceCondemnAll()
+    for chain in all chains:
+      ChainCondemnAll(chain)
+ +
ChainCondemnAll(chain):
+  for PoolGen in GenDesc 0 of chain:
+    for Seg in (PoolGen->pool)->SegRing:
+      TraceWhiten(Seg)
+ +

Note that AMS pools have a Gen-0-only chain (and so get condemned).

+ +

Note that LO and AWL pools also have a Gen-0-only chain (and so get condemned). [This is despite their segment-placement preference being hardwired to SegPrefGen-number 1; yuk! RHSK 2006-12-01]

Triggering a minor collection

+

Condition

+ +

A minor collection is triggered if there's a chain whose GenDesc 0 is 'over capacity': the sum of the PoolGen 0 newSizes exceeds the GenDesc's capacity. (If there's a choice, pick the chain whose Gen 0 is most over capacity).

+ +

[Note that we only look at "newSize". I don't understand what this means, or how it differs from totalSize. (It may be a consequence of nailing, perhaps?). RHSK 2006-12-01]

+ + +

What to condemn

+ +

For the triggering chain, ChainCondemnAuto() finds the list of GenDescs to condemn: GenDesc 0 and each higher GenDesc that's also over its capacity. (That is: where the sum of newSizes exceeds capacity, as before).

+ +

These GenDescs have been recording the zoneset of all the segments ever added into that GenDesc, as long as the pool noted it by calling PoolGenUpdateZones(PoolGen, Seg).

+ +

ChainCondemnAuto() calls TraceCondemnZones() to condemn the full zoneset ever touched by any segment in any of the condemned GenDescs.

+ +

TraceCondemnZones() uses the SegFirst/SegNext() iterator, and for every segment that is wholly within the condemned zones, it calls TraceAddWhite(seg).

+ +

Progress of a collection

@@ -83,6 +175,7 @@
   2006-11-30  RHSK  Created, incomplete.
+  2006-12-01  RHSK  What triggers a GC?