簡體   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