1. 程式人生 > >Android程式崩潰除錯案例:Reference table overflow

Android程式崩潰除錯案例:Reference table overflow

問題描述:
起初發現一段程式在執行一段時間後發生崩潰。經過多次測試,發現程式規律性地每持續執行30分鐘必發生崩潰問題。崩潰時log記錄到如下內容:

ReferenceTable overflow (max=1024)
JNI pinned array reference table (0x6080b458) dump:
  Last 10 entries (of 1024):
     1023: 0x423b76d0 int[] (1 elements)
     1022: 0x4209cea0 int[] (1 elements)
     1021: 0x4209c890 int[] (1 elements)
     1020
: 0x42242198 int[] (1 elements) 1019: 0x421b7b60 int[] (1 elements) 1018: 0x420c0e08 int[] (1 elements) 1017: 0x42107c18 int[] (1 elements) 1016: 0x421078e8 byte[] (1 elements) 1015: 0x42116a18 int[] (1 elements) 1014: 0x42116408 int[] (1 elements) Summary: 1 of byte[] (1 elements) 1023
of int[] (1 elements) (1023 unique instances) Failed adding to JNI pinned array ref table (1024 entries) "main" prio=5 tid=1 RUNNABLE | group="main" sCount=0 dsCount=0 obj=0x417f5de0 self=0x417e44a8 | sysTid=7820 nice=0 sched=0/0 cgrp=apps handle=1074331988 | state=R schedstat=( 0 0 0 ) utm=972 stm=228 core=0
at libcore.icu.NativeDecimalFormat.formatLong(Native Method) at libcore.icu.NativeDecimalFormat.formatLong(NativeDecimalFormat.java:253) at java.text.DecimalFormat.format(DecimalFormat.java:684) at java.text.NumberFormat.format(NumberFormat.java:299) at java.text.DecimalFormat.format(DecimalFormat.java:702) at java.text.SimpleDateFormat.appendNumber(SimpleDateFormat.java:785) at java.text.SimpleDateFormat.append(SimpleDateFormat.java:676) at java.text.SimpleDateFormat.formatImpl(SimpleDateFormat.java:553) at java.text.SimpleDateFormat.format(SimpleDateFormat.java:818) at java.text.DateFormat.format(DateFormat.java:307) at com.tuyou.tsd.launcher.SleepingActivity.updateTime(SleepingActivity.java:206) at com.tuyou.tsd.launcher.SleepingActivity.access$1(SleepingActivity.java:204) at com.tuyou.tsd.launcher.SleepingActivity$2.handleMessage(SleepingActivity.java:66) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:136) at android.app.ActivityThread.main(ActivityThread.java:5146) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:732) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:566) at dalvik.system.NativeStart.main(Native Method) VM aborting Fatal signal 6 (SIGABRT) at 0x00001e8c (code=-6), thread 7820 (com.tuyou.tsd)

從列印的堆疊進行分析,一開始認為是updateTime()中呼叫的DateFormat.format()導致的問題,因為updateTime()方法在一個定時器執行緒中,每隔一秒鐘觸發執行一次。檢視format()方法發現該方法的實現如下:

return format(date, new StringBuffer(), new FieldPosition(0)).toString();

所以一開始懷疑是頻繁的建立StringBuffer和FieldPosition物件有可能導致JVM來不及進行垃圾回收最終導致了引用表溢位的錯誤。再之後嘗試著複用StringBuffer和FieldPosition物件例項,以及將部分程式碼註釋掉,但問題仍然存在(執行30分鐘後報出引用表溢位錯誤,但打印出的堆疊內容不同)。這時開始懷疑問題可能另有原因。

於是首先單獨寫了一個定時器更新時間的小程式進行測試,連續執行一個小時沒有出現問題,由此可以判斷定時器並非是導致引用表錯誤的根源。這時再仔細看log的這幾句:

ReferenceTable overflow (max=1024)
...
  Summary:
        1 of byte[] (1 elements)
     1023 of int[] (1 elements) (1023 unique instances)
Failed adding to JNI pinned array ref table (1024 entries)

仔細想想出現的問題是引用表的內容超出了1024個的限制,內容是1個byte[]和1023個int[]。並且最後一句顯示向JNI指向的陣列引用表新增失敗。由此分析問題應該出在JNI呼叫上。於是查詢程式中的JNI部分,發現瞭如下兩個函式:

JNIEXPORT jint
Java_com_tuyou_tsd_common_util_TsdHelper_readport(JNIEnv* env, jobject thiz,int fd,jbyteArray buf,jint size)
{
    unsigned char *buf_char = (char*)((*env)->GetByteArrayElements(env,buf, NULL));
    return read(fd, buf_char,  size);
}

JNIEXPORT jint
Java_com_tuyou_tsd_common_util_TsdHelper_writeport(JNIEnv* env, jobject thiz,int fd,jbyteArray buf,jint size)
{
    unsigned char *buf_char = (char*)((*env)->GetByteArrayElements(env,buf, NULL));
    return write(fd, buf_char,  size);
}

正是這兩個函式中引用了GetByteArrayElements但是之後沒有將該物件釋放,而readport這個函式在程式執行時在另外一個定時器執行緒中每2秒被呼叫一次,所以真正導致出錯的地方在這裡。

找到根源後解決方法就簡單了,只需將上面兩段函式改寫,在返回前將引用的buffer物件釋放即可。修改後如下:

JNIEXPORT jint
Java_com_tuyou_tsd_common_util_TsdHelper_readport(JNIEnv* env, jobject thiz,int fd,jbyteArray buf,jint size)
{
    unsigned char *buf_char = (char*)((*env)->GetByteArrayElements(env,buf, NULL));
    read(fd, buf_char,  size);

    int result = buf_char != NULL ? buf_char[0] : -1;

    (*env)->ReleaseByteArrayElements(env, buf, buf_char, JNI_ABORT);

    LOGD("read from port result: %d", result);
    return result;
}

JNIEXPORT jint
Java_com_tuyou_tsd_common_util_TsdHelper_writeport(JNIEnv* env, jobject thiz,int fd,jbyteArray buf,jint size)
{
    unsigned char *buf_char = (char*)((*env)->GetByteArrayElements(env,buf, NULL));
    int result = write(fd, buf_char,  size);

    (*env)->ReleaseByteArrayElements(env, buf, buf_char, JNI_ABORT);

    LOGD("write to port result: %d", result);
    return result;
}

最後再次測試,程式執行後再未發生崩潰問題。

相關推薦

Android程式崩潰除錯案例Reference table overflow

問題描述: 起初發現一段程式在執行一段時間後發生崩潰。經過多次測試,發現程式規律性地每持續執行30分鐘必發生崩潰問題。崩潰時log記錄到如下內容: ReferenceTable overflow (max=1024) JNI pinned array r

Android程式崩潰處理

由於Android手機型號,廠商等很多,我們不能保證測試時候沒問題的程式,在各種手機上都沒問題。 當出現問題,程式崩潰時,我們可以設定對應的監聽,將對應的報錯資訊記錄下來,上傳至伺服器。 一、原理 在Thread類中,有一個介面 UncaughtExceptionHandl

android程式崩潰了卻沒法通過log檢視錯誤日誌

接一個bugly就可以了,在bugly上直接檢視錯誤資訊。BUGLY的文件寫的很清楚,流程我就不寫了,附上鍊接:https://cas.bugly.qq.com/cas/login?service=https%3A%2F%2Fbugly.qq.com%2Fv2%2Fworkb

Android程式崩潰異常處理框架

目前我已經把框架放在了github了,地址如下:https://github.com/msdx/android-crash 使用方法見github上面的README.md。 本專案相關jar包已釋出在jcenter,如果你使用gradle構建工具,可以直接新增依賴,具體見

通過wifi除錯android程式 無線除錯模式

資料線丟了,不想花錢去買,在網上看了看,android手機居然可以通過wifi進行程式的除錯,太好了,自己搞了一下,雖然網上寫的很詳細,但是還是有些問題,記錄下來,下次參考。 1.首先讓android手機監聽指定的埠:   這一步需要使用shell,因此手機上要有終端模擬器

Android程式編譯時報錯duplicate entry: android/support/v4/content/res/TypedArrayUtils.class

  為了解決這個報錯,弄到晚上快12點,現在懷著激動的心情記錄一下解決過程: 報錯全部內容如下: Error:Execution failed for task ':app:transfor

jni 記憶體洩露 local reference table overflow (max=512)

01-02 00:02:35.064: E/dalvikvm(4223): JNI ERROR (app bug): local reference table overflow (max=512) 向JNI傳遞大量的資料,或new出大量物件時,如果不及時釋放,則會造成上述

gdb除錯(3)觀察點和程式崩潰

$ gdb main ... (gdb) r Starting program: /home/akaedu/main 12345678 input=12345678 *** stack smashing detected ***: /home/akaedu/main terminated ======= Ba

樹莓派Android Things物聯網開發GitHub案例程式彙總

Welcome to code samples for Android Things. Here you will find code snippets and tutorials to help you build embedded applications and integrate hardware p

Android 簡單案例繼承BaseAdapter實現Adapter

for ack import apt ret bsp position hang layout import android.view.LayoutInflater; import android.view.View; import android.view.ViewGr

Android 簡單案例onSaveInstanceState 和 onRestoreInstanceState

ted bsp raw hand current div set for hot import android.app.Activity; import android.os.Bundle; import android.view.View; import android

Android 簡單案例可移動的View

bool fst boolean store import cup tcl etc last CrossCompatibility.rar 1. VersionedGestureDetector.java import android.content.Context; i

Cordova開發Android程式筆記一開發環境搭建

  Cordova開發Android程式筆記一:開發環境搭建   一、Java開發環境搭建   參考資料:Eclipse+ADT+Android SDK 搭建安卓開發環境  https://www.cnblogs.com/zh719588366/p/

網易MuMu模擬器除錯Android程式

在除錯模擬器時,發現網易 MuMu 模擬器無法直接除錯 Android 程式。下面分享一下除錯的方法: 1. 開啟網易 MuMu 模擬器 很重要,如果不開啟,下面操作完了,也是徒勞的。 2. 開啟安裝目錄 開啟 mumu 模擬器的安裝目錄 3. 開啟 cmd.ex

Android Studio 開啟除錯 時 提示could not connect to remote progress Aborting debug session

    1. 在 AndroidMenifest.xml  新增: android:debuggable="true"  允許除錯。 <application android:debuggable="true" andr

Android 應用程式崩潰日誌捕捉

程式崩潰是應用迭代中不可避免的問題,即使有著5年或者10年經驗的程式猿也無法完全保證自己的程式碼沒有任何的bug導致崩潰,現在有一些第三方平臺可以幫助我們蒐集應用程式的崩潰,比如友盟,詳情如下圖 雖然能夠看到崩潰的日誌以及機型等,但還是不是很方便,如果需要精確定位的話需要使用者提供崩潰的時間點、機型

android 廣播+服務+Application結合案例獲取所有安裝應用的資訊並展示到listview上,結合SearchView進行檢索

效果圖: 思路: 1、建立自定義Application,在其onCreate()回撥方法中啟動一個Service,在Service中開啟一個Thread執行緒,在該執行緒中,使用PackageManger類(主要職責是管理應用程式包)的getInstalledAp

逮蝦戶!Android程式除錯竟簡單如斯

PS:行吧,不用百度了,逮蝦戶是《頭文字D》的一首配樂《Deja vu》,中文諧音 “逮蝦戶”,飆車漂移專用BGM,有時音樂響起也暗示著:開車。 當然本節討論的不是開車,而是Android開發中老生常談的程式除錯。 一個開發仔的日常離不開:寫BUG和解BUG,特別是多人

Android平臺程式崩潰的型別及原因列舉

Android平臺程式崩潰大家都應該遇到過,force close和ANR應該是大家遇到較多的。 這裡把Android平臺程式崩潰的各種型別做一個簡述和原因列舉。 1.ANR(可見ANR): 發生場景:應用發生ANR。 崩潰症狀:系統彈出視窗詢問使用者選擇“Force Close”或

C語言除錯記憶體訪問出錯而引起的程式崩潰問題

在寫程式碼的時候,經常碰到由於記憶體訪問出錯而導致程式崩潰。當代碼量比較多的時候,根本不知道程式錯在哪裡,只能不斷猜測程式碼出錯的地方,將其註釋掉還會不會出現程式崩潰,這種方法雖然最後也能找到問題所在,但是會耗費大量時間。 linux下除錯通常會生成core d