You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

minSDK≥22调用free()触发内存错误,minSDK=21运行正常

Android API 22+ JNI内存分配差异与free报错修复

核心原因

API 22及以上的Android系统,JNI层内存管理有两处关键变化,直接触发你的free错误:

  1. 字符串内存所有权规则变更
    API21及以下,GetStringUTFChars返回的指针可能指向libc malloc分配的堆内存,直接free不会报错;但API22+开始,为了性能优化,该函数大概率返回JVM内部共享内存的指针,这类内存禁止用free释放,必须通过ReleaseStringUTFChars归还给JVM。
  2. 内存分配器的严格性提升
    API22起,bionic libc的malloc/free实现新增了严格的非法指针检测机制。如果代码存在重复释放、释放未分配指针,或者跨模块分配/释放内存(比如JNI用malloc分配,Java层间接释放),API21时可能静默忽略,但API22+会直接抛出Invalid address...错误。

修复步骤

  • 修正字符串内存释放方式:如果filePaths[i]是通过GetStringUTFChars获取的C字符串指针,立刻替换free(filePaths[i])为(*env)->ReleaseStringUTFChars(env, javaStringObj, filePaths[i])(其中javaStringObj是对应的Java字符串对象)。
  • 确保分配与释放匹配:如果filePaths[i]是你手动用malloc/calloc分配的内存,必须用同libc的free释放,禁止混用JNI的内存释放函数;如果是通过JNIEnv分配的内存(比如NewByteArray),必须用对应的Release函数。
  • 排查野指针/重复释放:添加日志打印,确认每个指针在释放前的状态,避免重复释放或释放未初始化的非法地址。

代码示例修正

假设原错误代码片段:

// 假设filePaths是存储Java字符串的数组
jstring* filePaths = (jstring*)malloc(sizeof(jstring) * fileCount);
// ... 填充filePaths逻辑
for (int i = 0; i < fileCount; i++) {
    const char* cPath = (*env)->GetStringUTFChars(env, filePaths[i], NULL);
    // ... 使用cPath做业务逻辑
    free((void*)cPath); // API22+此处报错
}
free(filePaths);

修正后代码:

jstring* filePaths = (jstring*)malloc(sizeof(jstring) * fileCount);
// ... 填充filePaths逻辑
for (int i = 0; i < fileCount; i++) {
    const char* cPath = (*env)->GetStringUTFChars(env, filePaths[i], NULL);
    // ... 使用cPath做业务逻辑
    (*env)->ReleaseStringUTFChars(env, filePaths[i], cPath); // 正确释放JNI字符串内存
}
free(filePaths); // 手动malloc的数组,用free释放合法

内容的提问来源于stack exchange,提问作者nima

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 08:35:13