ソースコード中に、全ての要素が定数であるような構造体が出現することがある。 これを定数構造体と呼ぶ。例を以下に示す。
[1, a, 10, [2, x]]
foo([1,2], bar, 3)
プログラムを実行する際には、最終的にこれらの構造をメモリ中に置くこととなる。 Naiveには、この構造の組み立ては動的に行う(つまり、定数でなかった場合 と同様に行う)が、すべてが定数である場合には、あらかじめ静的に 構造を作成しておくことが可能であり、これは、以下の意味での最適化になる。
foo(X) :- X=[1,2,3]なる述語で、
foo(X)が幾度も呼びだされる場合)、
静的に1つ確保することによりメモリを節約できることがあることがある
(静的に確保してしまうため、GCの対象にはならず、領域が不要となっても
領域の回収はできないため、必ずしも常に節約になるとは限らない)。
例えば、foo([1,2,3])という構造は以下のようにメモリ中に置かれる。
static Const q cons_const_0[] = { /* (1) */
NILATOM,
makeint(3),
};
static Const q cons_const_1[] = { /* (2) */
makecons(cons_const_0),
makeint(2),
};
static Const q cons_const_2[] = { /* (3) */
makecons(cons_const_1),
makeint(1),
};
static Const q funct_const_3[] = { /* (4) */
makesym(functor_foo_1),
makecons(cons_const_2),
};
Cでは、参照される変数を 参照する側よりも先に定義する必要があるため、ボトムアップに出力される。
まず(1)で、[3] がq型の配列cons_const_0 として出力されている。
makeintによりタグを付けていること、先にCDRが出ていることに注意。
次に(2)で、その[3]へのポインタにconsタグを付加し(makecons)、CDRとし、
さらにmakeint(2)をCARとして、[2,3]が作成される。
同様に、(3)で、[1,2,3]が作成される。
最後に(4)では、fooに対してのファンクタIDと、[1,2,3]へのポインタを
並べることにより、foo([1,2,3])が生成される。実際にこの構造を利用する時
には、makefunc(funct_const_3) としてコード中で参照される。
以上で判明するように、定数構造体については、その実体はヒープ中にとられない。 KLICのGCでは、ヒープ外へのポインタ(REF, CONS, FUNCタグつきのもの)を 発見したときには、そのポインタをコピーするだけで、その先はコピーの対象と しない。よって、定数構造体についてはGC時にコピーがなされない。 つまり、長期間参照されるような定数構造体については、 GC時にコピーをしない、という最適化も行われていることになる。