keigoi's ojacare advices

けいごさんに camljava/ojacare の問題点を呟いていただきました。ちょっと追えなくなりそうだったのでまとめることにしました。
0
Keigo Imai @keigoi

. @camlspotter あー、http://t.co/IpS6sHok のDalvikVMのバグでcamljavaだかO'jacareが落ちる話ですかね。それならパッチを見ればわかると思います(これから準備します)が、メモリ管理については私も何もやっていないに等しいです…

2012-06-05 20:40:52
Keigo Imai @keigoi

@camloeba そっちでしたか。 当たり前のことしか言えませんが、 ocaml側のオブジェクトがGCされ時にJavaのオブジェクトをデレファレンスDeleteLocalRef? これはcamljavaの問題ですね。あとJava側のオブジェクトがGCされる前には(続)

2012-06-05 20:56:39
Keigo Imai @keigoi

@keigoi @camloeba (承前)OCaml側のオブジェクトを解放する必要があります(Object.finalizeをオーバーライドしてOCaml側のオブジェクトをデリファレンス)。O'jacareが生成するJavaコードの問題ですが、これは必要ないかもしれません。

2012-06-05 20:59:12
Keigo Imai @keigoi

@keigoi @camloeba (承前)これ以外に、多数のJavaクラス(512個)をOCaml側に登録する場合、main関数で多くのクラスをアロケートしすぎて落ちますが、これはクラスのnewの時点でアロケートするように変えればなんとかなるはずです。今晩ソース探しときます

2012-06-05 21:01:53
Keigo Imai @keigoi

何かO'jacareの初期化のためにlazy_tとか使っているのだけど何のためだったか全く思い出せない 微妙な循環依存を解消するために使った気がするんだけど生成されたコード見ないと…

2012-06-06 00:50:14
Keigo Imai @keigoi

そうだ思い出した。普通のJVMだとAllocObjectでメモリを確保してポインタを取ってきた後、OCaml側で確保してから、CallNonvirtualVoidMethodでコンストラクタを呼べるが DalvikVMにはバグがありVMごと落ちる。(続)

2012-06-06 01:01:49
Keigo Imai @keigoi

@keigoi (承前)そんな方法でコンストラクタを呼ぶのは旧いJVMのJNIだけの話だったので問題にならなかった。今のJVMはNewObject一発でアロケートとコンストラクタ呼び出しが同時に行われる。しかしO'Jacareではそれは困る。なぜかというと(続)

2012-06-06 01:08:01
Keigo Imai @keigoi

@keigoi (承前)OCamlのラッパーオブジェクトの初期化時にJavaのオブジェクトを渡したいが、コンストラクタ呼出自体はOCamlのオブジェクトを確保した後に行いたいからだ。そこでNewObjectへの呼び出しをlazyで遅延し、OCaml側の初期化後にforceする(続

2012-06-06 01:11:00
Keigo Imai @keigoi

@keigoi (承前)なぜそんな面倒なことになったのか詳細は思い出せない… DalvikVMのバグは http://t.co/uYQVfAg5 で報告して、その後fixされたようだった。 しかし普通はNewObjectで初期化するので誰もこんなバグは踏まないはずだ:p

2012-06-06 01:13:55
Keigo Imai @keigoi

たぶんこれ後から読んでもよくわからんな

2012-06-06 01:15:07
Keigo Imai @keigoi

あとVMごと落ちるというのは嘘 そこまでひどくない

2012-06-06 01:16:33
Keigo Imai @keigoi

メタプログラミングなのでソースだけではわかりにくい。camlp5により生成されたプログラムを全体読まないといかん。

2012-06-06 01:19:30
Keigo Imai @keigoi

@camloeba コンパイル通るかすらためしていませんが、参考まで https://t.co/3D9k7juZ

2012-06-06 01:54:22
Keigo Imai @keigoi

@keigoi もっと言うと"ocaml側とjava側の循環参照をどう作るか"という問題になっていた。java側でアロケーションと初期化を分ける方法はDalvikVMのバグのせいで使えなかったので、ocaml側で遅延評価とvalue recursionでスマートに解決したのだった

2012-06-06 10:16:52
Keigo Imai @keigoi

@keigoi 他に、制御の構造とメモリ管理が関係する問題がある。その最たる例はJNIのFindClassで、これはローカル参照を返す。ローカル参照はJNIメソッドが終了すると自動的に解放されるが、その代わり512個までしか参照できない。(続)

2012-06-06 10:31:38
Keigo Imai @keigoi

@keigoi (承前) http://t.co/YavadTM6 より。しかしOjacareはメソッド呼び出し/フィールド参照毎にfind_classするのでどんどん参照が増えてゆき、最終的にはあふれる仕組みになっている。そこで、(続)

2012-06-06 10:37:18
Keigo Imai @keigoi

@keigoi (承前)最初にfind_classした後はOCaml側でクラスへの参照をキャッシュし続けるようにした。ただ問題はまだある。Android側にメインがあるので、メソッド呼び出しが終了したら参照が無効になってしまう!致命的なバグだけど、(続)

2012-06-06 10:39:36
Keigo Imai @keigoi

@keigoi (承前)結局これはローカル参照をグローバル参照に変換しておけばOK. 結局そこまでやらなかったけど、それほど難しくないはず。 むしろGCをうまく連携させるのが重要という気もするけど、これも使い方によるかも

2012-06-06 10:41:58
Jun Furuse 🐫🌴 @camloeba

camljava の test/ みる限り OCaml 側の値を Java objetct にラップする際には GC がうまく行くようになっていると思う…んだけど

2012-06-07 10:30:56
Keigo Imai @keigoi

@camloeba あれ、ホントですね。それにくわえて、Java側からOCamlの値を持った場合でも正しく解放されるようです。出鱈目いってスミマセン。 ただやはり、find_classが返すローカル参照が解放されない問題がO'jacareに残っているような気がします。

2012-06-07 12:33:07
Jun Furuse 🐫🌴 @camloeba

@keigoi いえ、GC周りは読ん出さらに試さないと。テストを書いたが解放されている気配がない…

2012-06-07 14:13:14
Jun Furuse 🐫🌴 @camloeba

@keigoi けいごさん、CamlJava にバグがあると思う。少なくともパッチ当たってる版

2012-06-07 19:31:09
Jun Furuse 🐫🌴 @camloeba

camljava_AllocObject() で AllocObject して、作られたオブジェクトに対し参照が作られる。それを alloc_jobject() に渡してそこでまた参照作っている。この時点で参照二つ。なのに OCaml 側で GC しても一つしか解放されない

2012-06-07 19:39:34
Jun Furuse 🐫🌴 @camloeba

僕はこういうGC追うの下手だから間違ってるかもだが、camljava_AllocObjectで一つ参照をDelしたら Java の finalizer を呼び出し始めた まあ間違ってるかも知れない

2012-06-07 19:42:23