1. 程式人生 > >JNI引用溢位導致的重啟問題分析

JNI引用溢位導致的重啟問題分析

問題描述

JNI全域性引用異常導致的重啟問題JNI ERROR (app bug): global reference table overflow (max=51200)'

Log

pid: 1279, tid: 2518, name: Binder:1279_9>>> system_server <<<

signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------

Abort message: 'art/runtime/indirect_reference_table.cc:132] JNI ERROR (app bug): global reference table overflow (max=51200)'

x00000000000000000x100000000000009d6x20000000000000006x30000000000000008

x40000000000000166x50000800000000000x60000007f0a5ab000x7000000000000000c

x80000000000000083x9ffffffffffffffdfx100000000000000000x110000000000000001

x120000000000000010x130000000000000030x14ffffffffffffffffx15ffffffffffffffff

x160000007f069f9ed0x170000007f069a278cx180000000000000000x190000007eddecf4f8

x200000000000000006x210000007eddecf450x22000000000000000dx230000007f05ffe000

x240000007f05f4b52bx250000007f05f85440x260000007eddece4f1x270000007f05ffcda0

x280000000000002ff0x290000007eddece3d0x300000007f0699fbb8

sp0000007eddece3b0pc0000007f069a2794pstate 0000000060000000

backtrace:

#00 pc 000000000006d794/system/lib64/libc.so (tgkill+8)

#01 pc 000000000006abb4/system/lib64/libc.so (pthread_kill+64)

#02 pc 0000000000024098/system/lib64/libc.so (raise+24)

#03 pc 000000000001c93c/system/lib64/libc.so (abort+52)

#04 pc 000000000043581c/system/lib64/libart.so (_ZN3art7Runtime5AbortEPKc+464)

#05 pc 00000000000e5e7c/system/lib64/libart.so (_ZN3art10LogMessageD2Ev+1592)

#06 pc 000000000024dd48/system/lib64/libart.so (_ZN3art22IndirectReferenceTable3AddEjPNS_6mirror6ObjectE+308)

#07 pc 00000000002f2468/system/lib64/libart.so (_ZN3art9JavaVMExt12AddGlobalRefEPNS_6ThreadEPNS_6mirror6ObjectE+60)

#08 pc 000000000032de8c/system/lib64/libart.so (_ZN3art3JNI12NewGlobalRefEP7_JNIEnvP8_jobject+596)

#09 pc 0000000000101454/system/lib64/libandroid_runtime.so (_ZN7android20javaObjectForIBinderEP7_JNIEnvRKNS_2spINS_7IBinderEEE+428)

#10 pc 00000000000f5a3c/system/lib64/libandroid_runtime.so

#11 pc 000000007564f254/data/dalvik-cache/arm64/[email protected]@boot-framework.oat (offset 0x19fc000)

log初步分析

根據log,查詢到是在frameworks/base/core/jni/android_util_Binder.cppjavaObjectForIBinder方法中呼叫NewGlobalRef時出現的問題

547 jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)

548 {

549if (val == NULL) return NULL;

585jobject refObject = env->NewGlobalRef(

586env->GetObjectField(object, gBinderProxyOffsets.mSelf));

587val->attachObject(&gBinderProxyOffsets, refObject,

588jnienv_to_javavm(env), proxy_cleanup);

這裡NewGlobalRef操作後,沒有看到明顯的DeleteGlobalRef操作。會不會是沒有進行DeleteGlobalRef操作導致的溢位呢?

解決嘗試

frameworks/base/core/jni/android_util_Binder.cpp進行新增env->DeleteGlobalRef(refObject);

進行回收操作

547 jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)

548 {static int scount = 0;//add,記錄呼叫次數

549if (val == NULL) return NULL;

585jobject refObject = env->NewGlobalRef(

586env->GetObjectField(object, gBinderProxyOffsets.mSelf));

587val->attachObject(&gBinderProxyOffsets, refObject,

588jnienv_to_javavm(env), proxy_cleanup);

595

596 scount++;

597 if (scount % 100 == 0)

598 {

599ALOGD("=====android_util_Binder.cpp, scount=%d\n", scount);

600 }

601

602 env->DeleteGlobalRef(refObject);

603// Note that a new object reference has been created.

604android_atomic_inc(&gNumProxyRefs);

605incRefsCreated(env);

606}

607

608return object;

609 }

編譯執行後,手機卻不能開機了。

分析

547 jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)

548 {

549if (val == NULL) return NULL;

585jobject refObject = env->NewGlobalRef(

586env->GetObjectField(object, gBinderProxyOffsets.mSelf));

587val->attachObject(&gBinderProxyOffsets, refObject,

588jnienv_to_javavm(env), proxy_cleanup);

在呼叫中,valBpBinder585行進行了NewGlobalRef操作後,接著在587行呼叫了attachObject方法,檢視該方法

BpBinder.cpp

void BpBinder::attachObject(

const void* objectID, void* object, void* cleanupCookie,

object_cleanup_func func)

{

AutoMutex _l(mLock);

ALOGV("Attaching object %p to binder %p (manager=%p)", object, this, &mObjects);

mObjects.attach(objectID, object, cleanupCookie, func);

}

其中,object_cleanup_func是函式指標,

typedef void (*object_cleanup_func)(const void* id, void* obj, void* cleanupCookie);

傳入的值為proxy_cleanup

static
{
}

BpBinder::attachObject方法中又呼叫了mObjects.attach(objectID, object, cleanupCookie, func);mObjectsBpBinder的成員變數。ObjectManager是其內部類。

 

void BpBinder::ObjectManager::attach(

const void* objectID, void* object, void* cleanupCookie,

IBinder::object_cleanup_func func)

{

entry_t e;

e.object = object;

e.cleanupCookie = cleanupCookie;

e.func = func;

if (mObjects.indexOfKey(objectID) >= 0) {

ALOGE("Trying to attach object ID %p to binder ObjectManager %p with object %p, but object ID already in use",

objectID, this,object);

return;

}

mObjects.add(objectID, e);

}

由於mObjectsBpBinder的成員變數,在BpBinder物件析構的時候,mObjects也會析構。

BpBinder::ObjectManager::~ObjectManager()

{

kill();

}

void BpBinder::ObjectManager::kill()

{

const size_t N = mObjects.size();

ALOGV("Killing %zu objects in manager %p", N, this);

for (size_t i=0; i<N; i++) {

const entry_t& e = mObjects.valueAt(i);

if (e.func != NULL) {

e.func(mObjects.keyAt(i), e.object, e.cleanupCookie);

}

}

mObjects.clear();

}

之前傳入的proxy_cleanup會被執行。

static
{
}

在這裡,對

585jobject refObject = env->NewGlobalRef(

586env->GetObjectField(object, gBinderProxyOffsets.mSelf));

Google的原始碼中考慮到了釋放問題。

所以,之前新增的直接釋放操作

602 env->DeleteGlobalRef(refObject);

是有問題的,進而導致了系統不能開機。

我們可以在art/runtime/indirect_reference_table.cc:

IndirectRef IndirectReferenceTable::Add(uint32_t cookie, mirror::Object* obj)方法中新增log列印來對引用數量進行跟蹤:

LOG(ERROR) << "JNI ERROR Test (app bug): " << kind_ << " table , topIndex= " << topIndex<< "\n";

列印結果為

01-01 08:18:58.363 14177-14189/? E/art: JNI ERROR Test (app bug): global reference table , topIndex= 596

01-01 08:18:58.363 14177-14189/? E/art: JNI ERROR Test (app bug): local reference table , topIndex= 0

這樣,就可以大致定位到出現大量洩漏的時間點。

相關推薦

JNI引用溢位導致問題分析

問題描述 JNI全域性引用異常導致的重啟問題JNI ERROR (app bug): global reference table overflow (max=51200)' Log pid: 1279, tid: 2518, name: Binder:1279_9

展訊平臺 kernel分析套路總結

一.初步定為分析 在ylog的phone.info中搜索關鍵詞 bootmode 例如: [ro.bootmode]: [panic] 可以確定是kenel panic導致的手機重啟  二.Kernel Panic的產生的原因 panic 是英文中是驚慌的

Android 第三方開啟App後現Launcher開啟導致的問題

這暫且做一個備忘錄 問題 第一次遇到這個問題,測試同學說: 每次第一次安裝App後,開啟至第二級介面,退至後臺,然後再從Launcher介面點選Icon圖示啟動,會發現App會重新啟動,跳至首頁,而不是跳至上次開啟的第二級介面。但是如果把程序kill掉

小米華為某些機型存在, Home 鍵讓 APP 後臺執行, 重新開啟 APP 導致的解決方案

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if ((getIntent().getFlags() &a

Gong服務實現平滑分析

平滑重啟是指能讓我們的程式在重啟的過程不中斷服務,新老程序無縫銜接,實現零停機時間(Zero-Downtime)部署; 平滑重啟是建立在優雅退出的基礎之上的,之前一篇文章介紹了相關實現:Golang中使用Shutdown特性對http服務進行優雅退出使用總結 目前實現平滑重啟的主要策略有兩種: 方案一:我們的

彈出SD卡導致問題分析

2018-10-10   在Android8.0上,安裝SD卡,設定為內部儲存,然後把安裝的應用move到SD卡上,開啟應用,然後在setting裡彈出(reject)SD卡,會發生重啟。 log 01-01 21:04:55.321858 1050 1081 D Pack

VS2012 啟動效能分析導致電腦問題解決方法

貌似是隻有Intel 的  cpu會這樣。。一點啟動效能分析,電腦重啟。。。   解決方法,cmd執行,添加註冊表:   reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Man

notification使用不當導致的宕機問題分析(Could not copy bitmap to parcel blob. )

前言 前段時間遇到了一個宕機重啟問題,比較複雜,涉及到多方面的知識,我也分析了很長的時間,期間學到了很多東西,現在把分析的過程整理一下,希望可以給大家一點幫助和啟發,同時也幫助自己再鞏固一下。 一、問題的復現 首先說一下問題最開始的分析思路以及復現的過程,log 中最核心的部

故障分析:核心引數設定不當導致資料庫異常

編輯手記:資料庫中每一個不起眼的引數,都有其內部的原理,不可隨意更改。今天分享一則因核心引數SEMOPM設定太小,加上在業務高併發時段LGWR寫入太慢,系統呼叫失敗,最終資料庫異常宕機的案例。 故障現象 資料庫CRASH,在CRASH前,ALERT中顯示如下的日誌內容 我們看到中間有27300和2

VS2015啟用效能分析(profilling)導致電腦的解決辦法

只要一點選“啟動分析”,電腦就會自動重啟,這是因為intel cpu的漏洞導致的,因此只會修復漏洞即可。或者如下修改登錄檔也可以解決問題:reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session 

修改hostname導致mysqlslave失敗的修復方法

修改hostname導致mysql重啟slave失敗的修復方法修改hostname導致mysql重啟slave失敗的修復方法(只針對於把slave的信息存在文件裏面會出現這種情況,如果存在表裏就不會有這種問題發生):有時候我們很早之前修改完主機名後,跑了好幾個月後,突然系統出問題,重啟了數據庫,發現start

Linux fstab修改不當導致開機fsck失敗而主機無法

fsck linux 重啟失敗 今天,廣州河源的地市技術通知我,他們的機房斷電了,數據庫服務器重啟後rac2主機丟失了data3數據目錄;然後,想調整該目錄開機自動掛載,開機卻卡在了如下界面:從報錯界面看,是開機文件系統檢查fsck失敗了,問題可能是fstab文件配置問題。於是,遠程讓他輸

Centos6.2 強制系統後導致系統文件損壞系統無法啟動

centos6.2 強制重啟系統後導致系統文件損壞系統無法啟動 Centos6.2 強制重啟系統後導致系統文件損壞系統無法啟動今天遇到一個比較尷尬的問題,一個客戶的服務器由於服務器被強制重啟造成磁盤損壞,在次啟動服務器的時候發現報錯系統無法啟動.啟動到這裏提示輸入密碼,尷尬的是客戶竟

使用FreeRTOS在SD卡驅動使用非系統延時導致上電不工作的情況

new i開啟 ask 函數 fault 思想 初始化 font 是否 一、問題描述在一個使用FreeRTOS的工程中,只做了SD卡的驅動,由於RTOS使用了Systick,故非系統延時函數使用的是 DWT中的時鐘周期(CYCCNT)計數功能,但是在SD卡驅動中使用了這個非

【troubleshooting】記一次Kafka集群導致消息復消費問題處理記錄

進程 pid 導致 set pic 方法 sum tails log 因需要重啟了Kafka集群,重啟後發現部分topic出現大量消息積壓,檢查consumer日誌,發現消費的數據竟然是幾天前的。由於平時topic消息基本上無積壓,consumer消費的數據都是最新的,明顯

mysql內存不斷被占用,導致每隔一個多月就自動,修改數據庫配置後,問題解決

mysql 內存 占用 innodb  這個月初,通過zabbix監控發現有1臺mysql數據庫的從庫內存剩余空間不斷降低。檢查以往的監控歷史圖表,發現由於內存占用不斷增大,每隔一個多月,就會因為內存嚴重不足,導致這臺服務器的1個mysql實例(端口:3316)重啟。數據庫實例重啟之後,內存被大量釋放,但經過

小心了,這個設置會導致你的vm時被強制裝系統!

含義 start 就是 rom 如果 翻譯 volatile root hat 主標題:小心了,這個設置會導致你的vm重啟時被強制重裝系統! 副標題:關於計算方案中"可變"的含義 初次使用者容易犯的錯誤,誤認為該選項是此處設置的各項參數,在日後使用過程中可以調整。其實不是

linux異常處理:selinux配置錯誤導致無法

嚴格 log htm 1.2 模式 想要 process info 磁盤 點擊返回自學Linux集錦 linux異常處理:selinux配置錯誤導致無法重啟 一次linux無法重啟異常記錄: 當時第一反應就是梳理最近的配置變更,特別是能預知相關的就是selinux配置變

1.報出問題: Please change caller according to com.intellij.openapi.project. IndexNotReadyException documentation 2.分析問題: 提示資訊,不影響編譯 3.解決方案: AS

1.報出問題: Please change caller according to com.intellij.openapi.project. IndexNotReadyException documentation 2.分析問題: 提示資訊,不影響編譯 3.解

Spring Developer Tools 原始碼分析:三、自動配置'

接上文 Spring Developer Tools 原始碼分析:二、類路徑監控,接下來看看前面提到的這些類是如何配置,如何啟動的。 spring-boot-devtools 使用了 Spring Boot 的自動配置方式,我們先關注本地開發環境中自動重啟的部分。 在 LocalDevToolsAut