いさぽん部屋(isapon.com)

ゲーム系プログラマによる特に方針のないブログ。技術系とカレー、ラーメンネタ多めだったはずが、最近はダイエットネタ多め。

local reference table overflow の時の確認方法

Android 向けの開発をしていたところ、local reference table overflow なるエラーが起きた。


解決方法は簡単(NDKならね)なのですが、修正する前にどんな状態なのか調べたかったので何か良い調査方法はないかと探してみました。


VMDebug.dumpReferenceTables() を使う

dalvik.system.VMDebug.dumpReferenceTables()
(dumpReferenceTables  ()V)

これを呼ぶだけ。すると logcat にローカル参照テーブルとグローバル参照テーブルの一覧が出力されます。


しかし実機で出力されない

最初、これを呼び出しても何も起こらず変だな~と思ったら、Android本体のソースコードで、ログの出力部分がON/OFFできるようになっているのが見つかりました。


つまり、実機ではログ出力がOFFになっている場合があります。この場合はもうどうしようもありません。そうした場合は素直にエミュレータを使うのがBestです。


おまけ:そもそも local reference table overflow ってなによ?

Android のAPIはJavaで作られているものがほとんどです(とはいえ、Android本体のソースコードを追えば、結局はその中身のほとんどは c++ なのですが)。


AndroidのJavaVM(Javaで作られてプログラムを動かすプログラムのこと)はdalvikと名前がついています。そしてこのdalvikは基本的にJavaVMと割と近い互換性を持っています。


dalvikは本家JavaVM同様に、ローカル参照とグローバル参照という仕組みを持っており、これによって、メモリを勝手に開放しないようにしています。グローバルとローカルの違いについては面倒なのでここでは説明を避けますが、今回の問題はローカル参照です。


ローカル参照はc++的な感じでいうと、いわゆるスタックからの参照に相当すると思ってください。基本的には関数を抜けたら手動で開放すべきですが、一応Javaのスレッドが終了すると、そのスレッドで使用されていたローカル参照は根こそぎ破棄してくれます。なので「大体の場合は開放を忘れてもそれっぽく動き続ける」わけです。


んで、このローカル参照ですが、1スレッド当たり 512 個までという制限がついています。なので、メインスレッドでループし続けると不足してしまうわけですね。