From e15ec6daeaa65fc8d0fd3e8b83a3a95bd2d7e4f2 Mon Sep 17 00:00:00 2001 From: qiuyucheng Date: Mon, 5 Oct 2026 20:49:15 +0800 Subject: [PATCH] [CSDK] Release JNI local references in Configuration get and set leaked two local refs per call. Configuration now stores the Hadoop Configuration class and instance as global refs and releases them in its destructor. Fixes #4403 Signed-off-by: qiuyucheng --- sdk/CSDK/src/CarbonSchemaReader.cpp | 4 +- sdk/CSDK/src/CarbonSchemaReader.h | 4 +- sdk/CSDK/src/Configuration.cpp | 60 +++++++++++++++++++++++++---- sdk/CSDK/src/Configuration.h | 3 ++ 4 files changed, 60 insertions(+), 11 deletions(-) diff --git a/sdk/CSDK/src/CarbonSchemaReader.cpp b/sdk/CSDK/src/CarbonSchemaReader.cpp index 5fcd4271410..c0bf1913342 100644 --- a/sdk/CSDK/src/CarbonSchemaReader.cpp +++ b/sdk/CSDK/src/CarbonSchemaReader.cpp @@ -34,7 +34,7 @@ jobject CarbonSchemaReader::readSchema(char *path) { return readSchema(path, conf); } -jobject CarbonSchemaReader::readSchema(char *path, Configuration conf) { +jobject CarbonSchemaReader::readSchema(char *path, Configuration &conf) { if (path == NULL) { throw std::runtime_error("path parameter can't be NULL."); } @@ -54,7 +54,7 @@ jobject CarbonSchemaReader::readSchema(char *path, Configuration conf) { return result; } -jobject CarbonSchemaReader::readSchema(char *path, bool validateSchema, Configuration conf) { +jobject CarbonSchemaReader::readSchema(char *path, bool validateSchema, Configuration &conf) { if (path == NULL) { throw std::runtime_error("path parameter can't be NULL."); } diff --git a/sdk/CSDK/src/CarbonSchemaReader.h b/sdk/CSDK/src/CarbonSchemaReader.h index 5ea5f9f4c1f..abfbeccbff0 100644 --- a/sdk/CSDK/src/CarbonSchemaReader.h +++ b/sdk/CSDK/src/CarbonSchemaReader.h @@ -60,7 +60,7 @@ class CarbonSchemaReader { * end point and other conf with this * @return schema */ - jobject readSchema(char *path, Configuration conf); + jobject readSchema(char *path, Configuration &conf); /** * read schema from path, @@ -73,7 +73,7 @@ class CarbonSchemaReader { * end point and other conf with this * @return schema */ - jobject readSchema(char *path, bool validateSchema, Configuration conf); + jobject readSchema(char *path, bool validateSchema, Configuration &conf); /** * read schema from path, diff --git a/sdk/CSDK/src/Configuration.cpp b/sdk/CSDK/src/Configuration.cpp index 0f73fa71c02..0c9a120ac64 100644 --- a/sdk/CSDK/src/Configuration.cpp +++ b/sdk/CSDK/src/Configuration.cpp @@ -20,21 +20,51 @@ Configuration::Configuration(JNIEnv *env) { this->jniEnv = env; - configurationClass = env->FindClass("org/apache/hadoop/conf/Configuration"); + jclass localClass = env->FindClass("org/apache/hadoop/conf/Configuration"); + if (localClass == NULL) { + throw std::runtime_error("Can't find the class in java: org/apache/hadoop/conf/Configuration"); + } + configurationClass = (jclass) env->NewGlobalRef(localClass); + env->DeleteLocalRef(localClass); if (configurationClass == NULL) { throw std::runtime_error("Can't find the class in java: org/apache/hadoop/conf/Configuration"); } initID = jniEnv->GetMethodID(configurationClass, "", "()V"); if (initID == NULL) { + jniEnv->DeleteGlobalRef(configurationClass); + configurationClass = NULL; throw std::runtime_error("Can't find init it in java: org/apache/hadoop/conf/Configuration"); } - configurationObject = jniEnv->NewObject(configurationClass, initID); - if (configurationClass == NULL) { + jobject localObject = jniEnv->NewObject(configurationClass, initID); + if (localObject == NULL) { + jniEnv->DeleteGlobalRef(configurationClass); + configurationClass = NULL; + throw std::runtime_error("Can't create object in java: org/apache/hadoop/conf/Configuration"); + } + configurationObject = jniEnv->NewGlobalRef(localObject); + jniEnv->DeleteLocalRef(localObject); + if (configurationObject == NULL) { + jniEnv->DeleteGlobalRef(configurationClass); + configurationClass = NULL; throw std::runtime_error("Can't create object in java: org/apache/hadoop/conf/Configuration"); } } +Configuration::~Configuration() { + if (jniEnv == NULL) { + return; + } + if (configurationObject != NULL) { + jniEnv->DeleteGlobalRef(configurationObject); + configurationObject = NULL; + } + if (configurationClass != NULL) { + jniEnv->DeleteGlobalRef(configurationClass); + configurationClass = NULL; + } +} + void Configuration::check() { if (configurationClass == NULL) { throw std::runtime_error("configurationClass can't be NULL. Please init first."); @@ -61,10 +91,18 @@ void Configuration::set(char *key, char *value) { } } + jstring jKey = jniEnv->NewStringUTF(key); + jstring jValue = jniEnv->NewStringUTF(value); jvalue args[2]; - args[0].l = jniEnv->NewStringUTF(key); - args[1].l = jniEnv->NewStringUTF(value); + args[0].l = jKey; + args[1].l = jValue; jniEnv->CallObjectMethodA(configurationObject, setID, args); + if (jKey != NULL) { + jniEnv->DeleteLocalRef(jKey); + } + if (jValue != NULL) { + jniEnv->DeleteLocalRef(jValue); + } } @@ -86,12 +124,20 @@ char *Configuration::get(char *key, char *defaultValue) { } } + jstring jKey = jniEnv->NewStringUTF(key); + jstring jDefaultValue = jniEnv->NewStringUTF(defaultValue); jvalue args[2]; - args[0].l = jniEnv->NewStringUTF(key); - args[1].l = jniEnv->NewStringUTF(defaultValue); + args[0].l = jKey; + args[1].l = jDefaultValue; jobject result = jniEnv->CallObjectMethodA(configurationObject, getID, args); char *str = (char *) jniEnv->GetStringUTFChars((jstring) result, JNI_FALSE); + if (jKey != NULL) { + jniEnv->DeleteLocalRef(jKey); + } + if (jDefaultValue != NULL) { + jniEnv->DeleteLocalRef(jDefaultValue); + } jniEnv->DeleteLocalRef(result); return str; } diff --git a/sdk/CSDK/src/Configuration.h b/sdk/CSDK/src/Configuration.h index 4f7b518848e..ef968f6fa27 100644 --- a/sdk/CSDK/src/Configuration.h +++ b/sdk/CSDK/src/Configuration.h @@ -58,6 +58,9 @@ class Configuration { * @param env JNI env */ Configuration(JNIEnv *env); + ~Configuration(); + Configuration(const Configuration &) = delete; + Configuration &operator=(const Configuration &) = delete; /** * configure parameter, including ak,sk and endpoint