昨日の続き。
dynamic-windを使えば、昨日の

他の問題点としては、S式バトラーのように、複数のevalを同時に起動して、継続を使ってコルーチン的に動きまわるような場合には、正常にメモリ使用量を取る事が出来ない。

を一応、解決できる事に気付いた。
(但し、運が悪ければ、メモリ使用判定が片方のevalにばかり偏ってしまう可能性は残るが)

(use eval-sv)
(use gauche.parameter)
(use util.list)
(define-values (eval/sv env) (make-eval/sv :isolate-port? #f))
(define start-size (make-parameter #f))
(define runup-size (make-parameter 0))
(define limit-size (make-parameter #f))

(define (get-used-memory)
  (let1 stat (gc-stat)
    (- (car (assoc-ref stat :total-heap-size))
       (car (assoc-ref stat :free-bytes)))))

(define (sv type symbol expr args return except)
  (define (over?)
    (let ((now-used (- (get-used-memory) (start-size)))
          (old-used (runup-size))
          )
      (< (limit-size) (+ now-used old-used))))

  (when (over?)
    (gc)
    (when (over?)
      (except "out of memory" (get-used-memory))))
  (apply expr args))

(define (eval/memlimit expr limit)
  ;; 諸事情により、parameterizeは使わずに、自前でparameterを管理する
  (let ((current-runup-size 0)
        (original-start-size #f)
        (original-runup-size #f)
        (original-limit-size #f))
    (dynamic-wind
      (lambda ()
        ;; parameterizeする
        (set! original-start-size (start-size))
        (set! original-runup-size (runup-size))
        (set! original-limit-size (limit-size))
        (gc)
        (start-size (get-used-memory))
        (runup-size current-runup-size)
        (limit-size limit)
        )
      (lambda ()
        (eval/sv expr sv))
      (lambda ()
        (gc)
        ;; current-runup-sizeに、今回の処理で増えたメモリ増分値を足しておく
        ;; (継続再起動時の為に)
        (set! current-runup-size (+ current-runup-size
                                    (- (get-used-memory) (start-size))))
        ;; unparameterizeする
        (start-size original-start-size)
        (runup-size original-runup-size)
        (limit-size original-limit-size)
        ;; 無駄に参照を握らないように、明示的に解放しておく
        (set! original-start-size #f)
        (set! original-runup-size #f)
        (set! original-limit-size #f)
        ))))

簡単に動作確認を取る。
(複数のevalをコルーチン的に同時に動かす動作確認は、面倒なので省略する。)

(eval/memlimit
  `(let baibain ((kuri-manjuh '(1)))
     (display (,start-size))
     (display " ")
     (display (,runup-size))
     (display " ")
     (display (,limit-size))
     (display " ")
     (display (,get-used-memory))
     (display " ")
     (display (length kuri-manjuh))
     (newline)
     (baibain (append kuri-manjuh kuri-manjuh)))
  10)
3678208 0 10 3678208 1
3678208 0 10 3678208 2
3678208 0 10 3678208 4
3678208 0 10 3678208 8
3678208 0 10 3678208 16
3678208 0 10 3678208 32
3678208 0 10 3678208 64
3678208 0 10 3678208 128
3678208 0 10 3678208 256
3678208 0 10 3678208 512
3678208 0 10 3678208 1024
3678208 0 10 3678208 2048
3678208 0 10 3678208 4096
3678208 0 10 3678208 8192
3678208 0 10 3678208 16384
*** ERROR: out of memory 3682304
Stack Trace:
_______________________________________

一見、正常に動作しているように見えるが、何度も実行すると、昨日のバージョンとは違い、少しずつメモリ使用の閾値が増えていってしまっている。

(何度も実行した後の結果)

5369856 0 10 5369856 1
5369856 0 10 5369856 2
5369856 0 10 5369856 4
5369856 0 10 5369856 8
5369856 0 10 5369856 16
5369856 0 10 5369856 32
5369856 0 10 5369856 64
5369856 0 10 5369856 128
5369856 0 10 5369856 256
5369856 0 10 3690496 512
5369856 0 10 3690496 1024
5369856 0 10 3690496 2048
5369856 0 10 3690496 4096
5369856 0 10 3690496 8192
5369856 0 10 3690496 16384
5369856 0 10 3690496 32768
5369856 0 10 3784704 65536
5369856 0 10 4313088 131072
5369856 0 10 5365760 262144
*** ERROR: out of memory 7442432
Stack Trace:
_______________________________________

これを見る限りでは、(gc)のタイミングではなく、実際に何らかの処理を行っている最中に、使用メモリが突然減っているように見える。
これが原因で、二回目以降に実行したeval/memlimit起動時に、使用メモリの底状態の測定ができずに、結果として正しく機能しなくなってしまっている。


どうしたものか……。


Gauche単体としては、メモリの回復量だけを見るならば、メモリリークはしていないようなので、(gc)と(gc-stat)を使うのは非推奨という事なのか。リファレンスにも書かれてないし。


駄目だったら、やっぱりSCM_MALLOCに手を入れるしかなさそうだ……。
あとでソース見る。


追記:
簡単にソース見た。
src/extlib.stub にあるのは、

(define-cproc gc () (call <void> "GC_gcollect"))

なので、別に(gc)が無効化されている様子は無かった。