使用AAssetManager打开文件时崩溃问题求助
AAssetManager调用AAssetManager_open时崩溃的问题排查与解决
崩溃堆栈
#00 pc 00000000000cdd91 /apex/com.android.runtime/lib64/bionic/libc.so (pthread_mutex_lock+1) (BuildId: fa337969c798946280caa45e2d71a2e7) #01 pc 0000000000050115 /system/lib64/libc++.so (std::__1::mutex::lock()+5) (BuildId: 3324cfa90a3aa967ca9e5c4269b1b7f2) #02 pc 0000000000018875 /system/lib64/libandroid.so (AAssetManager_open+53) (BuildId: 094d5e744838e61070f3b00f0a8d3c31)
该崩溃由无效Java对象引用导致,现有实现代码如下:
Java层代码
public class MainActivity extends SDLActivity { private AssetManager mgr; native void initAManager(AssetManager mgr); @Override protected void onCreate(Bundle savedInstanceState) { mgr = this.getAssets(); super.onCreate(savedInstanceState); initAManager(mgr); } /* ... */ }
Native层代码
static jobject omgr = NULL; static AAssetManager* gmgr = NULL; JNIEXPORT void JNICALL Java_com_example_MainActivity_initAManager(JNIEnv* env, jobject thiz, jobject mgr) { omgr = (*env)->NewGlobalRef(env, mgr); gmgr = AAssetManager_fromJava(env, omgr); } /* ... */ int open_file(struct ctx mctx, char* name) { if((*mctx->env)->IsSameObject(mctx->env, omgr, NULL)) { log_print("Asset manager object is invalid"); // 日志中从未出现该行! } AAsset* asset = AAssetManager_open(gmgr, name, AASSET_MODE_RANDOM); // 该行崩溃 /* ... */ }
已尝试的方案:
- 应用后期通过JNI动态获取AssetManager,但对象会被垃圾回收变为NULL
- 更新工具链后问题依旧
解决思路与代码优化
1. 修正对象有效性检查逻辑
IsSameObject无法准确判断已被GC回收的Java对象,改用IsValidObject做有效性校验:
int open_file(struct ctx mctx, char* name) { JNIEnv* env = mctx->env; if (omgr == NULL || !(*env)->IsValidObject(env, omgr)) { log_print("Asset manager object is invalid"); return -1; } // ... }
2. 避免存储全局AAssetManager指针
AAssetManager_fromJava返回的指针依赖于Java层AssetManager对象的生命周期,一旦Java对象被回收,该指针会变成野指针。建议每次使用时通过全局引用的Java对象重新获取:
static jobject omgr = NULL; JNIEXPORT void JNICALL Java_com_example_MainActivity_initAManager(JNIEnv* env, jobject thiz, jobject mgr) { // 先释放旧引用,避免内存泄漏 if (omgr != NULL) { (*env)->DeleteGlobalRef(env, omgr); } omgr = (*env)->NewGlobalRef(env, mgr); } int open_file(struct ctx mctx, char* name) { JNIEnv* env = mctx->env; if (omgr == NULL || !(*env)->IsValidObject(env, omgr)) { log_print("Asset manager object is invalid"); return -1; } AAssetManager* gmgr = AAssetManager_fromJava(env, omgr); if (gmgr == NULL) { log_print("Failed to retrieve AAssetManager"); return -1; } AAsset* asset = AAssetManager_open(gmgr, name, AASSET_MODE_RANDOM); // ... }
3. 维护Java层与Native层引用的生命周期同步
在Activity销毁时主动释放Native层的全局引用,避免内存泄漏和无效引用:
Java层补充代码:
@Override protected void onDestroy() { destroyAManager(); super.onDestroy(); } native void destroyAManager();
Native层补充代码:
JNIEXPORT void JNICALL Java_com_example_MainActivity_destroyAManager(JNIEnv* env, jobject thiz) { if (omgr != NULL) { (*env)->DeleteGlobalRef(env, omgr); omgr = NULL; } }
4. 确保线程安全
如果open_file在非JNI调用线程执行,需要先将线程Attach到VM并获取当前线程的JNIEnv:
int open_file(struct ctx mctx, char* name) { JNIEnv* env = NULL; // 假设mctx中保存了JavaVM指针 if ((*mctx->vm)->AttachCurrentThread(mctx->vm, &env, NULL) != JNI_OK) { log_print("Failed to attach thread"); return -1; } // 执行AssetManager操作... (*mctx->vm)->DetachCurrentThread(mctx->vm); return 0; }
内容的提问来源于stack exchange,提问作者scored
相关产品推荐
相关产品推荐

