山本和彦 ?@kazu_yamamoto 教えて詳しい人:GHC では ByteString が pinned object なんですが、どうやって GC に回収されるんでしょうか?
詳しくはないけど、ざっと追いかけてみる。
GHC 7.4.1 rts/sm/Storage.c:743
// If we don't have a block of pinned objects yet, or the current
// one isn't large enough to hold the new object, allocate a new one.
if (bd == NULL || (bd->free + n) > (bd->start + BLOCK_SIZE_W)) {
// The pinned_object_block remains attached to the capability
// until it is full, even if a GC occurs. We want this
// behaviour because otherwise the unallocated portion of the
// block would be forever slop, and under certain workloads
// (allocating a few ByteStrings per GC) we accumulate a lot
// of slop.
//
// So, the pinned_object_block is initially marked
// BF_EVACUATED so the GC won't touch it. When it is full,
// we place it on the large_objects list, and at the start of
// the next GC the BF_EVACUATED flag will be cleared, and the
// block will be promoted as usual (if anything in it is
// live).
ACQUIRE_SM_LOCK;
if (bd != NULL) {
dbl_link_onto(bd, &g0->large_objects);
g0->n_large_blocks++;
g0->n_new_large_words += bd->free - bd->start;
}
cap->pinned_object_block = bd = allocBlock();
RELEASE_SM_LOCK;
initBdescr(bd, g0, g0);
bd->flags = BF_PINNED | BF_LARGE | BF_EVACUATED;
bd->free = bd->start;
}
rts/sm/GC.c:1279
// mark the large objects as from-space
for (bd = gen->large_objects; bd; bd = bd->link) {
bd->flags &= ~BF_EVACUATED;
}
以上をまとめると:
- pinned objectはpinned_object_blockに配置してGCがさわらないようにBF_EVACUATEDフラグをたてておく。
- pinned_object_blockがいっぱいになったら、ブロックごとlarge_objects listにうつして、新しいpinned_object_blockをつくる。
- large_objects listの中身は、GC開始時にBF_EVACUATEDフラグをオフにされるので、GCで回収されるようになる。