繁体   English   中英

SoundPoolThread 通过 JNI 错误导致 SIGSEGV“访问已删除的全局引用”

[英]SoundPoolThread causing SIGSEGV via JNI ERROR "accessed deleted global reference"

我的 Android 应用程序(minSdkLevel:2.2,targetSdkLevel:3.0,在 Nexus 7 和 Android 4.2 上测试)在加载阶段执行以下操作:

  1. 创建一个SoundPool并在其上注册一个OnLoadCompleteListener
  2. 开始加载声音。 每当加载声音时, SoundPool调用我的回调方法。
  3. 如果加载过程被用户中断,则调用SoundPool.release()
  4. (如果release()已经被调用并且之前开始的声音加载完成,即系统调用我的回调,那么我的应用程序检测到我的SoundPool已经为null并忽略回调,所以它是安全的)。

在 Nexus 7 上进行测试,在调用SoundPool.release()SoundPool.release()出现以下错误(logcat):日志猫

即事件顺序可能如下:

  1. 由于我的SoundPool.load(...)调用,系统开始异步加载声音
  2. 我离开了加载屏幕,所以SoundPool.release()被调用并且SoundPool设置为null
  3. (?) 系统完成了较早的声音加载完成回调,但遇到了一些错误。

我检查了Android的源代码,并为JNI代码SoundPool.release()确实删除SoundPool通过JNI中DeleteGlobalRef 它使用弱引用在 Java 级别存储SoundPool引用。

我无法重现该错误,可能是因为由于不确定性,我无法重现确切条件。 系统应该正确处理SoundPool在异步加载声音时可能会被释放的情况,但似乎在某些极少数情况下会出现错误。 (请注意,我的代码版本SoundPool一个nullcheck后只出现一次,因此错误是不是在我的代码肯定)。

知道为什么在 Android 中会发生这样的错误吗? 从理论上讲,我的上述怀疑是否正确? 如何保护我的应用程序免受此 Android 错误的影响? 也许我可以尝试在一个布尔值中设置SoundPool应该被释放,等到所有回调返回,然后在最后一个回调中释放它(基于这个布尔值)? 我想不出任何其他解决方法,但我想确定它至少会起作用。

正如您所说,由于竞争条件,这似乎是 Android 中的一个错误。 根据用户 CommonsWare 的要求,我打开了一个带有回溯的错误: http : //code.google.com/p/android/issues/detail? id=53043

违规代码似乎在 Android 的 media/jni/soundpool/SoundPool.cpp 中,它执行以下操作:

void SoundPool::notify(SoundPoolEvent event)
{
    Mutex::Autolock lock(&mCallbackLock);
    if (mCallback != NULL) {
        mCallback(event, this, mUserData);
    }
}

看起来 mCallback 是一个可以被垃圾收集器删除的 Java 对象,因此当调用 notify 时,它会尝试引用此对象,并且会发生“访问已删除的全局引用”崩溃。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM