1 2 3 4 5 | object Tekito { lib.setFunction(idx, new JnaCallback { def onMessage(msg : String) = println( "onMessage " + idx + ": " + msg) }) } |
で、なんとなく次のように変えてみる。
1 2 3 4 5 6 | object Tekito { def callback = new JnaCallback { def onMessage(msg : String) = println( "onMessage " + idx + ": " + msg) } lib.setFunction(idx, callback) } |
ただ、コールバックのセットをし直すと、コールバックがまた返ってくるようになることを発見したので、症状が出る前と後で
1 | println(Tekito.callback) |
1 2 3 4 | 正常時 models.Tekito$$anon$1@5ca99bc コールバックが返ってこなくなった後 models.Tekito$$anon$1@3833089c |
c側でコールバックを保持しているのは、ただの関数ポインタなので、これではコールバックは返ってこない。
{これ、どうしてくれようか}
と思ったが、素直に下のようにしてみたら
1 2 3 4 5 6 | object Tekito { val callback = new JnaCallback { def onMessage(msg : String) = println( "onMessage " + idx + ": " + msg) } lib.setFunction(idx, callback) } |
私は、JVMやscalaのメモリ管理を詳しく知らないので、これで本当にアドレスが固定されるのか確信がないのだが、とりあえず今のところはアドレスが変ってしまうケースはなくなった。
なので、
「scalaからJNAのコールバックをセットする時は、コールバックをvalに入れておく」
をお勧めします。
追記 2013/06/19
後で気が付いたのですが、コールバックオブジェクトを変数に入れておかないと、そのオブジェクトはどこからも参照されていない状態になりGCが動いた時に掃除されてしまうので、コールバックが迷子になる。が正解っぽいです。
コールバックが迷子になるタイミングが不規則だったのは、GCが動くタイミングが不規則だからで、c側でコールバックを保持していてもJVMのメモリとは当然関係ないので、GCに片付けられてしまうということのようです。