厳密でなくてもいいなら、eval/svと(gc-stat)を使えば、擬似的にメモリ使用量を制御できる事に気付いた。

(use eval-sv)
(use gauche.parameter)
(use util.list)
(define-values (eval/sv env) (make-eval/sv :isolate-port? #f))
(define original-size (make-parameter #f))
(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?)
    (let1 mem (get-used-memory)
      (< (+ (original-size) (limit-size)) mem)))
  (when (over?)
    (gc)
    (when (over?)
      (except "out of memory" (get-used-memory))))
  (apply expr args))

(define (eval/memlimit expr limit)
  (gc) ; これが無いと正しく測定できない
  (parameterize ((original-size (get-used-memory))
                 (limit-size limit))
    (eval/sv expr sv)))

試してみる。

(eval/memlimit
  `(let baibain ((kuri-manjuh '(1)))
     (display (length kuri-manjuh))
     (display " ")
     (display (,get-used-memory)) ; for debug
     (newline)
     (baibain (append kuri-manjuh kuri-manjuh)))
  10)
1 3665920
2 3665920
4 3665920
8 3665920
16 3665920
32 3665920
64 3665920
128 3665920
256 3665920
512 3665920
1024 3665920
2048 3665920
4096 3665920
8192 3665920
16384 3665920
32768 3665920
*** ERROR: out of memory 3780608
Stack Trace:
_______________________________________

何度か試してみたが、kuri-manjuhが65536個になるまで終了しない。
その時のメモリの変化量は114688。
一応機能はしているものの、なかなか大雑把だ。
どうしたものか。


他の問題点としては、S式バトラーのように、複数のevalを同時に起動して、継続を使ってコルーチン的に動きまわるような場合には、正常にメモリ使用量を取る事が出来ない。
これはちょっと困る。
とは言え、単純にeval/svが入れ子になる場合に対しては正しく機能する筈。


これは……微妙だ。
どうしよう。
もう少し考えよう。