メモリ不足ではまった

WIN32OLE を使ってタイプライブラリからオブジェクトをもらうテストをしていた。

オブジェクトをくれる関数には 8 個の引数があり、その組み合わせは全部で 7290 通り。

arg1 = [0, 1, 2]
arg2 = [false, true, nil]
  ...
arg1.product(arg2).product ...

引数の組み合わせを生成して each でガンガン呼び出しテストをしていたら、250 回目くらいで失敗する。
何回やっても 250 回前後で謎のエラー。

WIN32OLERuntimeError を調べてみたら「メモリが不足しています。」って?
ちゃんと後始末もしてるのに?

def test_foo(argv)
  types = [VT_I4, VT_BOOL, ...]
  m = @app.ole_method('getObj')
  o = @app._invoke(m.dispid, argv, types)
  ...
ensure
  o.Close       # 後始末
end

o が Ruby からアクセスできなくなっても WIN32OLE オブジェクトの参照カウンタは減らしてくれないみたい。

GC.start したら解決した。

def test_foo(argv)
  types = [VT_I4, VT_BOOL, ...]
  m = @app.ole_method('getObj')
  o = @app._invoke(m.dispid, argv, types)
  ...
ensure
  o.Close
  GC.start      # <= これ
end

正確には、前回 test_foo が呼ばれたときのゴミを回収してるんでしょうね。