Tech Racho エンジニアの「?」を「!」に。
  • 開発

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);

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


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。