まず、 ephemeron とは何か?ものすごく簡単に言えば循環構造を許す弱対といえる。SRFI-124で定義されている ephemeron は一種の鍵対で、鍵が値から参照されてたとしても、その参照のみが生きているのであれば GC 対象になるというもの。日本語は難しいのでコードで説明してみる。
(let* ((key (cons 1 2)) (value (cons key 1))) (make-ephemeron key value))こんなのが鍵が値から参照されている状態である。この場合だと、鍵は値のみから参照されているので、ephemeron を作った直後に GC が発生すればどちらも回収されるというものである。
さて、実際の挙動を観察してみよう。SRFI-124 によれば ephemeron は MIT Scheme または Racket でサポートされているという(ちなみに、Sagittarius にもなんちゃってはあるが Chibi Scheme と同様のバグを抱えている。っていうか、これ Boehm GC 上で実装できるの?) MIT Scheme は手元にないので Racket を使ってみる。コードは以下の通り:
#lang racket (define (make-weak v) (let* ((a (cons 1 2)) (b (cons a v))) (make-ephemeron a b))) (define e (make-weak 'a)) (write (ephemeron-value e)) (newline) (collect-garbage 'major) (write (ephemeron-value e)) (newline)出力結果は以下:
Welcome to DrRacket, version 6.3 [3m]. Language: racket; memory limit: 128 MB. ((1 . 2) . a) #fGC 後には ephemeron の値が回収されているのがわかる。
ちょっとした追記:
この挙動と何が違うのか考えて見たのだが、鍵となる実は既に Racket も使ってみていたのですが、すぐには壊れないみたい (?) なので、色々な事例で (理解のために) 挙動を観察するのに良い方法を模索していたのでした。 pic.twitter.com/jbicifloo7— 9b96faac591ad05eddec760eed2da2d5 齊藤敦志 (@SaitoAtsushi) 29 March 2018
a
が大域に設定されているのがまずいのかなぁというありきたりな推測。 set!
でリセットしているが、内部のどこかでは参照が生きているとかそんなのではないだろうか?流石に Racket の中まではわからないので推測に過ぎないが…