Skip to content

RapidOCR JNI:OcrResultUtils 循环内未 DeleteLocalRef,文本块多时可能撑爆 local reference table #575

Description

@QiuYucheng2003

问题

libs/rapidocr/src/main/cpp/src/OcrResultUtils.cpp 把 OCR 结果转成 Java 对象时,循环里创建的 JNI 局部引用用完后没有 DeleteLocalRef

这些辅助函数跑在同一次 JNI native 调用里,C++ 函数返回不会清 local ref。Android 默认 local reference table 大约 512 个槽。整页识别文本块一多,可能在 detect 返回前出现:

JNI ERROR: local reference table overflow

native 方法返回后 JVM 会清表,所以这不是跨调用的常驻泄漏,而是单次转换过程中的容量问题

代码

newJBoxPoint:每个点 NewObject 后加入 ArrayList,未释放 jPointnewJPoint 每次还 FindClass

for (auto point : boxPoint) {
    jobject jPoint = newJPoint(point);
    jniEnv->CallBooleanMethod(jList, jListAdd, jPoint);
    // 缺少:jniEnv->DeleteLocalRef(jPoint);
}

getTextBlocks 同样:

for (int i = 0; i < textBlocks.size(); ++i) {
    jobject jTextBlock = getTextBlock(textBlocks[i]);
    jniEnv->CallBooleanMethod(jList, jListAdd, jTextBlock);
    // 缺少:jniEnv->DeleteLocalRef(jTextBlock);
}

getTextBlock 里 newJBoxPoint、NewStringUTF、newJScoreArray、FindClass("...TextBlock") 的中间引用,在 NewObject 之后也没有删。一个框一般 4 个点,每个文本块会留下十几个 local ref。

add 之后 Java 列表已经持有对象,对应的局部引用应当立刻删掉。

构造函数里 NewObject 得到的 jOcrResult 是返回给 Java 的结果,不要删。需要删的是循环临时量和 FindClass / jStrRest 这类用完即弃的引用。


建议
1. CallBooleanMethod(..., add, x) 之后立刻 DeleteLocalRef(x)(jPoint、jTextBlock)。
2. getTextBlock 在 NewObject 之后释放 jBoxPint、jText、jCharScores、clazz。
3. FindClass 提到循环外做一次,或做成全局引用;不要每个点、每个 block 都 Find 一次。
4. 更稳妥:每次转换包一层 PushLocalFrame / PopLocalFrame,或用 RAII 管 local ref。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions