JNIでReferenceTable overflowが発生したのでDeleteLocalRefを使う

JNIの中でループ処理を行っていると、以下のようなエラーが発生することがあります。

ReferenceTable overflow (max=512)
Last 10 entries in JNI local reference table:

たとえば、Native側からJavaのRandomAccessFileにアクセスし、データを読み込む以下のようなコードがあります。

jobject rfile; // これはRandomAccessFileを指している
jmethodID methodID; // これはRandomAccessFile#read(byte[], int, int)のID

const int size = 1024;
void *buf = malloc(size);

// RandomAccessFile#readを呼び出し、Javaの配列jbufにデータを取得
jbyteArray jbuf = env->NewByteArray(size);
jint ret = env->CallIntMethod(rfile, methodID, jbuf, 
                  static_cast<jint> (0), 
                  static_cast<jint> (size));

// jbufからbufにデータをコピー
jboolean iscopy;
void *jbytes = env->GetPrimitiveArrayCritical(jbuf, &iscopy);
std::memcpy(buf, jbytes, ret);
env->ReleasePrimitiveArrayCritical(jbuf, jbytes, iscopy);

これを、1回のJNI呼び出しの中で数百回呼び出すと、上記エラーが発生します。
ファイルIOの代替としてランダムアクセスしていると、すぐに発生してしまいます。

エラーの内容は、NewByteArrayで作成されたJavaのオブジェクト(jbuf)が多すぎて、参照テーブルがあふれたというものです。
1回ごとにjbufの内容はCのbufにコピーしていて、これはもういらないので、

env->DeleteLocalRef(jbuf);

を毎回呼んでやることで解決できます。

Ruby on RailsによるWEBシステム開発、Android/iPhoneアプリ開発、電子書籍配信のことならお任せください この記事を書いた人と働こう! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

baba

ゆとりプログラマー。 高校時代から趣味でプログラミングを初め、そのままコードを書き続けて現在に至る。慶應義塾大学環境情報学部(SFC)卒業。BPS設立初期に在学中から参加している最古参メンバーの一人。Ruby on Rails、PHP、Androidアプリ、Windows/Macアプリ、超縦書の開発などを気まぐれにやる。軽度の資格マニアで、情報処理技術者試験(15区分 + 情報処理安全確保支援士試験)、技術士(情報工学部門)、CITP、Ruby Programmer Goldなどを保有。

babaの書いた記事

週刊Railsウォッチ

インフラ

BigBinary記事より

ActiveSupport探訪シリーズ