didi / Hummer

一套移动端高性能高可用的动态化跨端开发框架
https://hummer.didi.cn/
Apache License 2.0
1.34k stars 180 forks source link

Java_com_didi_hummer_core_engine_napi_jni_JSEngine_callFunction 内存泄漏 #447

Open wy676579037 opened 4 months ago

wy676579037 commented 4 months ago

案例: this.timer = setInterval(async () => { console.log('每隔 1s 执行一次'); }, 1000);

每次执行JSValue都会增加一个。

extern "C" JNIEXPORT jobject JNICALL Java_com_didi_hummer_core_engine_napi_jni_JSEngine_callFunction(JNIEnv *env, jclass clazz, jlong js_context, jlong thisObj, jlong funcObj, jobjectArray params) { auto globalEnv = JSUtils::toJsContext(js_context);

NAPIHandleScope handleScope;
napi_open_handle_scope(globalEnv, &handleScope);

NAPIValue jsThisObj = JSUtils::toJsValue(globalEnv, thisObj);
NAPIValue jsFuncObj = JSUtils::toJsValue(globalEnv, funcObj);
auto paramsCount = static_cast<int>(env->GetArrayLength(params));

if (jsFuncObj == nullptr) {
    return nullptr;
}

auto values = new NAPIValue[paramsCount];
for (int i = 0; i < paramsCount; i++) {
    jobject obj = env->GetObjectArrayElement(params, i);
    values[i] = JSUtils::JavaObjectToJsValue(globalEnv, obj);
    env->DeleteLocalRef(obj);
}

if (jsThisObj == nullptr) {
    jsThisObj = JSUtils::createJsUndefined(globalEnv);
}

NAPIValue result;
auto status = napi_call_function(globalEnv, jsThisObj, jsFuncObj, paramsCount, values, &result);
if (status == NAPIExceptionPendingException) {
    reportExceptionIfNeed(globalEnv);
    napi_close_handle_scope(globalEnv, handleScope);
    return nullptr;
}
delete[] values;

jobject r = JSUtils::JsValueToJavaObject(globalEnv, result, true);
napi_close_handle_scope(globalEnv, handleScope);
return r;

} 原因是每次调用 NAPIValue result; 都会返回一个Promise,导致JSUtils::JsValueToJavaObject(globalEnv, result, true)的使用做了强制+1,从而导致内存不释放

wy676579037 commented 4 months ago

async 会返回一个promise,普通的回调是正常的