jnienv::getstringutfchars返回const char*,需配对releasestringutfchars释放,直接赋值std::string后未释放会导致内存泄漏;处理中文、emoji等应优先用utf-16转换避免modified utf-8语义丢失。

JNIEnv::GetStringUTFChars 返回的是 const char*,不是 std::string
直接调用 GetStringUTFChars 只能拿到 C 风格字符串指针,它指向 JVM 内部缓冲区(可能只读、可能临时),不能直接赋给 std::string 构造函数后就不管了。常见错误是忘记释放或误用编码:
- 没调用
ReleaseStringUTFChars→ 内存泄漏(尤其在循环或高频调用中) - 用
GetStringUTFChars但传入非 UTF-8 字符(如中文、emoji)→ 返回乱码或截断(因为 Java String 是 UTF-16,GetStringUTFChars转的是 modified UTF-8,对 \u0000 和代理对有特殊处理) - 把返回的指针存为成员变量长期使用 → JVM 可能在下次 GC 或线程切换时使该地址失效
推荐做法:用 GetStringUTFChars + ReleaseStringUTFChars 配对构造 std::string
这是最常用且兼容性最好的方式,适用于绝大多数 JNI 层字符串传递场景(如日志、简单参数解析):
std::string jstring2string(JNIEnv* env, jstring jstr) {
if (jstr == nullptr) return {};
const char* cstr = env->GetStringUTFChars(jstr, nullptr);
if (cstr == nullptr) return {}; // OOM or invalid string
std::string str(cstr);
env->ReleaseStringUTFChars(jstr, cstr); // 必须配对!
return str;
}
注意:GetStringUTFChars 的第二个参数是 jboolean*,传 nullptr 表示“不关心是否返回拷贝”,JVM 自行决定;多数实现会返回拷贝,所以安全。
需要完整 Unicode 支持?改用 GetStringRegion + std::wstring + 转码
如果 Java 字符串含 BMP 外字符(如 ?、?)、或需精确保序/等价比较,GetStringUTFChars 的 modified UTF-8 会破坏语义(例如代理对被转成三字节序列,无法 round-trip)。此时应:
- 用
GetStringRegion或GetStringCritical拿到 UTF-16 编码的jchar* - 转成
std::u16string(C++11 起支持) - 再按需转为 UTF-8(用系统 API 或轻量库如
std::codecvt_utf8_utf16,但注意后者在 C++17 已弃用)
简单跨平台转 UTF-8 示例(不依赖第三方):
std::string jstring2utf8(JNIEnv* env, jstring jstr) {
if (jstr == nullptr) return {};
jsize len = env->GetStringLength(jstr);
std::u16string u16(len, u'\0');
env->GetStringRegion(jstr, 0, len, reinterpret_cast<jchar>(&u16[0]));
// 手动 UTF-16 → UTF-8(略去细节,实际需处理代理对)
// 更稳妥:用 ICU、boost.locale 或 C++20 std::text_encoding(尚未普及)
return convert_utf16_to_utf8(u16); // 你自己的实现
}</jchar>
性能敏感场景:避免无谓拷贝,优先复用缓冲区
高频调用(如每帧处理字符串)时,反复构造/析构 std::string 有开销。可考虑:
- 传入一个已分配的
std::string&引用,用.assign()复用内存 - 用
GetStringUTFRegion直接写入预分配的std::vector<char></char>缓冲区(需提前 reserve) - 若只是做简单判断(如是否为空、是否等于某常量),用
GetStringUTFLength+GetStringUTFChars对比 raw bytes,跳过std::string构造
特别注意:GetStringUTFLength 返回的是 UTF-8 字节数,不是 Java 中的 char 数量,别和 StringLength 混淆。
JNI 层字符串转换最易忽略的点是生命周期管理——GetStringUTFChars 的返回值必须与 ReleaseStringUTFChars 成对出现,哪怕函数中途 return 或 throw,也得确保释放。C++ RAII 可封装,但标准 JNI 不提供自动管理机制。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











