摘要:
?本文發(fā)現(xiàn)了一類OOM(OutOfMemoryError)函喉,這類OOM的特點(diǎn)是崩潰時java堆內(nèi)存和設(shè)備物理內(nèi)存都充足忠寻,探索并解釋了這類OOM拋出的原因瓦堵。
關(guān)鍵字:
?OutOfMemoryError 肛鹏,OOM,pthread_create failed , Could not allocate JNI Env
一. 引子
?對于每一個移動開發(fā)者蜒灰,內(nèi)存是都需要小心使用的資源牡直,而線上出現(xiàn)的OOM(OutOfMemoryError)都會讓開發(fā)者抓狂救恨,因?yàn)槲覀兺ǔQ稣痰闹庇^的堆棧信息對于定位這種問題通常幫助不大贸辈。
?網(wǎng)上有很多資料教我們?nèi)绾巍熬o衣縮食“的利用寶貴的堆內(nèi)存(比如,使用小圖片肠槽,bitmap復(fù)用等)擎淤,可是:
- 線上的OOM真的全是由于堆內(nèi)存緊張導(dǎo)致的嗎?
- 有沒有App堆內(nèi)存寬裕秸仙,設(shè)備物理內(nèi)存也寬裕的情況下發(fā)生OOM的可能嘴拢?
?內(nèi)存充裕的時候出現(xiàn)OOM崩潰?看似不可思議寂纪,然而席吴,最近筆者在調(diào)查一個問題的時候,通過自研的APM平臺發(fā)現(xiàn)公司的一個產(chǎn)品的大部分OOM確實(shí)有這樣的特征捞蛋,即:
- OOM崩潰時孝冒,java堆內(nèi)存遠(yuǎn)遠(yuǎn)低于Android虛擬機(jī)設(shè)定的上限,并且物理內(nèi)存充足拟杉,SD卡空間充足
?既然內(nèi)存充足庄涡,這時候?yàn)槭裁磿蠴OM崩潰呢?
二. 問題描述
?在詳細(xì)描述問題之前搬设,先弄清楚一個問題:
????什么導(dǎo)致了OOM的產(chǎn)生穴店?
下面是幾個關(guān)于Android官方聲明內(nèi)存限制閾值的API:
ActivityManager.getMemoryClass(): 虛擬機(jī)java堆大小的上限,分配對象時突破這個大小就會OOM
ActivityManager.getLargeMemoryClass():manifest中設(shè)置largeheap=true時虛擬機(jī)java堆的上限
Runtime.getRuntime().maxMemory() : 當(dāng)前虛擬機(jī)實(shí)例的內(nèi)存使用上限拿穴,為上述兩者之一
Runtime.getRuntime().totalMemory() : 當(dāng)前已經(jīng)申請的內(nèi)存泣洞,包括已經(jīng)使用的和還沒有使用的
Runtime.getRuntime().freeMemory() : 上一條中已經(jīng)申請但是尚未使用的那部分。那么已經(jīng)申請并且正在使用的部分used=totalMemory() - freeMemory()
ActivityManager.MemoryInfo.totalMem: 設(shè)備總內(nèi)存
ActivityManager.MemoryInfo.availMem: 設(shè)備當(dāng)前可用內(nèi)存
/proc/meminfo 記錄設(shè)備的內(nèi)存信息
????????圖2-1 Android內(nèi)存指標(biāo)
?通常認(rèn)為OOM發(fā)生是由于java堆內(nèi)存不夠用了贞言,即
Runtime.getRuntime().maxMemory()這個指標(biāo)滿足不了申請堆內(nèi)存大小時
????????圖2-2 Java堆OOM產(chǎn)生原因
?這種OOM可以非常方便的驗(yàn)證(比如: 通過new byte[]的方式嘗試申請超過閾值maxMemory()的堆內(nèi)存)斜棚,通常這種OOM的錯誤信息通常如下:
java.lang.OutOfMemoryError: Failed to allocate a XXX byte allocation with XXX free bytes and XXXKB until OOM
????????圖2-3 堆內(nèi)存不夠?qū)е碌腛OM的錯誤信息
?而前面已經(jīng)提到了,本文中發(fā)現(xiàn)的OOM案例中堆內(nèi)存充裕(Runtime.getRuntime().maxMemory()大小的堆內(nèi)存還剩余很大一部分)该窗,設(shè)備當(dāng)前內(nèi)存也很充裕(ActivityManager.MemoryInfo.availMem還有很多)弟蚀。這些OOM的錯誤信息大致有下面兩種:
- 這種OOM在Android6.0,Android7.0上各個機(jī)型均有發(fā)生酗失,文中簡稱為OOM一义钉,錯誤信息如下:
java.lang.OutOfMemoryError: Could not allocate JNI Env
????????圖2-4 OOM一的錯誤信息
- 集中發(fā)生在Android7.0及以上的華為手機(jī)(EmotionUI_5.0及以上)的OOM,簡稱為OOM二规肴,對應(yīng)錯誤信息如下:
java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Out of memory
????????圖2-5 OOM二的錯誤信息
三. 問題分析及解決
3.1 代碼分析
?Android系統(tǒng)中捶闸,OutOfMemoryError這個錯誤是怎么被系統(tǒng)拋出的夜畴?下面基于Android6.0的代碼進(jìn)行簡單分析:
- Android虛擬機(jī)最終拋出OutOfMemoryError的代碼位于 /art/runtime/thread.cc
void Thread::ThrowOutOfMemoryError(const char* msg)
參數(shù)msg攜帶了OOM時的錯誤信息
????????圖3-1 ART Runtime拋出的位置
- 搜索代碼可以發(fā)現(xiàn)以下幾個地方調(diào)用了上述方法拋出OutOfMemoryError錯誤
- 第一個地方是堆操作時
系統(tǒng)源碼文件:
/art/runtime/gc/heap.cc
函數(shù):
void Heap::ThrowOutOfMemoryError(Thread* self, size_t byte_count, AllocatorType allocator_type)
拋出時的錯誤信息:
oss << "Failed to allocate a " << byte_count << " byte allocation with " << total_bytes_free << " free bytes and " << PrettySize(GetFreeMemoryUntilOOME()) << " until OOM";
????????圖3-2 Java堆OOM
?這種拋出的其實(shí)就是堆內(nèi)存不夠用的時候,即前面提到的申請堆內(nèi)存大小超過了Runtime.getRuntime().maxMemory()
- 第二個地方是創(chuàng)建線程時
系統(tǒng)源碼文件:
/art/runtime/thread.cc
函數(shù):
void Thread::CreateNativeThread(JNIEnv* env, jobject java_peer, size_t stack_size, bool is_daemon)
拋出時的錯誤信息:
"Could not allocate JNI Env"
或者
StringPrintf("pthread_create (%s stack) failed: %s", PrettySize(stack_size).c_str(), strerror(pthread_create_result)));
????????圖3-3 線程創(chuàng)建時OOM
?對比錯誤信息删壮,可以知道我們遇到的OOM崩潰就是這個時機(jī)贪绘,即創(chuàng)建線程的時候(Thread::CreateNativeThread)產(chǎn)生的。
- 還有其他的一些錯誤信息如”[XXXClassName] of length XXX would overflow“是系統(tǒng)限制String/Array的長度所致央碟,不在本文討論之列税灌。
那么,我們關(guān)心的就是Thread::CreateNativeThread時拋出的OOM錯誤亿虽,創(chuàng)建線程為什么會導(dǎo)致OOM呢菱涤?
3.2 推斷
?既然拋出來OOM,一定是線程創(chuàng)建過程中觸發(fā)了某些我們不知道的限制洛勉,既然不是Art虛擬機(jī)為我們設(shè)置的堆上限粘秆,那么可能是更底層的限制。
?Android系統(tǒng)基于linux收毫,所以linux的限制對于Android同樣適用攻走,這些限制有:
- /proc/pid/limits 描述著linux系統(tǒng)對對應(yīng)進(jìn)程的限制,下面是一個樣例:
Limit Soft Limit Hard Limit Units
Max cpu time unlimited unlimited seconds
Max file size unlimited unlimited bytes
Max data size unlimited unlimited bytes
Max stack size 8388608 unlimited bytes
Max core file size 0 unlimited bytes
Max resident set unlimited unlimited bytes
Max processes 13419 13419 processes
Max open files 1024 4096 files
Max locked memory 67108864 67108864 bytes
Max address space unlimited unlimited bytes
Max file locks unlimited unlimited locks
Max pending signals 13419 13419 signals
Max msgqueue size 819200 819200 bytes
Max nice priority 40 40
Max realtime priority 0 0
Max realtime timeout unlimited unlimited us
????????圖3-4 Linux進(jìn)程限制示例
?用排除法篩選上面樣例中的limits:
- Max stack size此再,Max processes的限制是整個系統(tǒng)的陋气,不是針對某個進(jìn)程的,排除
- Max locked memory 引润,排除巩趁,后面會分析,線程創(chuàng)建過程中分配線程私有stack使用的mmap調(diào)用沒有設(shè)置MAP_LOCKED淳附,所以這個限制與線程創(chuàng)建過程無關(guān)
- Max pending signals议慰,c層信號個數(shù)閾值,無關(guān)奴曙,排除
- Max msgqueue size别凹,Android IPC機(jī)制不支持消息隊列,排除
?剩下的limits項(xiàng)中洽糟,Max open files這一項(xiàng)限制最可疑
?Max open files表示每個進(jìn)程最大打開文件的數(shù)目炉菲,進(jìn)程每打開一個文件就會產(chǎn)生一個文件描述符fd(記錄在/proc/pid/fd下面),這個限制表明fd的數(shù)目不能超過Max open files規(guī)定的數(shù)目坤溃。
?后面分析線程創(chuàng)建過程中會發(fā)現(xiàn)過程中涉有及到文件描述符拍霜。
- /proc/sys/kernel中描述的限制
?這些限制中與線程相關(guān)的是/proc/sys/kernel/threads-max,規(guī)定了每個進(jìn)程創(chuàng)建線程數(shù)目的上限薪介,所以線程創(chuàng)建導(dǎo)致OOM的原因也有可能與這個限制相關(guān)祠饺。
3.3 驗(yàn)證
下面對上述的推斷進(jìn)行驗(yàn)證,分兩步:本地驗(yàn)證和線上驗(yàn)收汁政。
- 本地驗(yàn)證:在本地驗(yàn)證推斷道偷,試圖復(fù)現(xiàn)與圖[2-4]OOM一與圖[2-5]OOM二所示錯誤消息一致的OOM
- 線上驗(yàn)收:下發(fā)插件缀旁,驗(yàn)收線上用戶OOM時確實(shí)是由于上面的推斷的原因?qū)е碌?/strong>。
本地驗(yàn)證
實(shí)驗(yàn)一:
?觸發(fā)大量網(wǎng)絡(luò)連接(每個連接處于獨(dú)立的線程中)并保持勺鸦,每打開一個socket都會增加一個fd(/proc/pid/fd下多一項(xiàng))
?注:不只有這一種增加fd數(shù)的方式并巍,也可以用其他方法,比如打開文件换途,創(chuàng)建handlerthread等等
- 實(shí)驗(yàn)預(yù)期:
當(dāng)進(jìn)程fd數(shù)(可以通過 ls /proc/pid/fd | wc -l 獲得)突破 /proc/pid/limits中規(guī)定的Max open files時履澳,產(chǎn)生OOM - 實(shí)驗(yàn)結(jié)果:
當(dāng)fd數(shù)目到達(dá) /proc/pid/limits中規(guī)定的Max open files時,繼續(xù)開線程確實(shí)會導(dǎo)致OOM的產(chǎn)生怀跛。錯誤信息及堆棧如下:
E/art: ashmem_create_region failed for 'indirect ref table': Too many open files
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.netease.demo.oom, PID: 2435
java.lang.OutOfMemoryError: Could not allocate JNI Env
at java.lang.Thread.nativeCreate(Native Method)
at java.lang.Thread.start(Thread.java:730)
......
????????圖3-5 FD數(shù)超限導(dǎo)致OOM的詳細(xì)信息
?可以看出,此OOM發(fā)生時的錯誤信息確與線上發(fā)現(xiàn)的OOM一的“Could not allocate JNI Env”吻合柄冲,因此線上上報的OOM一可能就是由FD數(shù)超限導(dǎo)致的吻谋,不過最終確定需要到線上進(jìn)行驗(yàn)證(下一小節(jié)).
?此外從ART虛擬機(jī)的Log中看出,還有一個關(guān)鍵的信息“ art: ashmem_create_region failed for 'indirect ref table': Too many open files”现横,后面會用于問題定位及解釋漓拾。
實(shí)驗(yàn)二:
?創(chuàng)建大量的空線程(不做任何事情,直接sleep)
實(shí)驗(yàn)預(yù)期:
當(dāng)線程數(shù)(可以在/proc/pid/status中的threads項(xiàng)實(shí)時查看)超過/proc/sys/kernel/threads-max中規(guī)定的上限時產(chǎn)生OOM崩潰實(shí)驗(yàn)結(jié)果:
- 在Android7.0及以上的華為手機(jī)(EmotionUI_5.0及以上)的手機(jī)產(chǎn)生OOM戒祠,這些手機(jī)的線程數(shù)限制都很小(應(yīng)該是華為rom特意修改的limits)骇两,每個進(jìn)程只允許最大同時開500個線程,因此很容易復(fù)現(xiàn)了姜盈。OOM時錯誤信息如下:
W libc : pthread_create failed: clone failed: Out of memory
W art : Throwing OutOfMemoryError "pthread_create (1040KB stack) failed: Out of memory"
E AndroidRuntime: FATAL EXCEPTION: main
Process: com.netease.demo.oom, PID: 4973
java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Out of memory
at java.lang.Thread.nativeCreate(Native Method)
at java.lang.Thread.start(Thread.java:745)
......
????????圖3-6 線程數(shù)超限導(dǎo)致的OOM詳細(xì)信息
?可以看出錯誤信息與我們線上遇到的OOM二吻合:"pthread_create (1040KB stack) failed: Out of memory"
?另外ART虛擬機(jī)還有一個關(guān)鍵Log:“pthread_create failed: clone failed: Out of memory”低千,后面會用于問題定位及解釋。
- 其他Rom的手機(jī)線程數(shù)的上限都比較大馏颂,不容易復(fù)現(xiàn)上述問題示血。但是,對于32位的系統(tǒng)救拉,當(dāng)進(jìn)程的邏輯地址空間不夠的時候也會產(chǎn)生OOM,每個線程通常需要mapp 1MB左右的stack空間(stack大小可以自行設(shè)置)难审,32為系統(tǒng)進(jìn)程邏輯地址4GB,用戶空間少于3GB亿絮。邏輯地址空間不夠(已用邏輯空間地址可以查看/proc/pid/status中的VmPeak/VmSize記錄)告喊,此時創(chuàng)建線程產(chǎn)生的OOM具有如下信息:
W/libc: pthread_create failed: couldn't allocate 1069056-bytes mapped space: Out of memory
W/art: Throwing OutOfMemoryError "pthread_create (1040KB stack) failed: Try again"
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.netease.demo.oom, PID: 8638
java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Try again
at java.lang.Thread.nativeCreate(Native Method)
at java.lang.Thread.start(Thread.java:1063)
......
????????圖3-7 邏輯地址空間占滿導(dǎo)致的OOM
線上驗(yàn)收及問題解決
?本地嘗試復(fù)現(xiàn)的OOM錯誤信息中圖[3-5]與線上OOM一情況比較吻合,圖[3-6]與線上OOM二的情況比較吻合派昧,但線上的OOM一真的時FD數(shù)目超限黔姜,OOM二真的是由于華為手機(jī)線程數(shù)超限的原因?qū)е碌膯幔孔罱K確定還需要取線上設(shè)備的數(shù)據(jù)進(jìn)行驗(yàn)證.
驗(yàn)證方法:
?下發(fā)插件到線上用戶蒂萎,當(dāng)Thread.UncaughtExceptionHandler捕獲到OutOfMemoryError時記錄/proc/pid目錄下的如下信息:
- /proc/pid/fd目錄下文件數(shù)(fd數(shù))
- /proc/pid/status中threads項(xiàng)(當(dāng)前線程數(shù)目)
- OOM的日志信息(出了堆棧信息還包含其他的一些warning信息
線上OOM一驗(yàn)證
?發(fā)生OOM一的線上設(shè)備中采集到的信息:
- /proc/pid/fd目錄下文件數(shù)與/proc/pid/limits中的Max open files 數(shù)目持平地淀,證明FD數(shù)目已經(jīng)滿了
- 崩潰時日志信息與圖[3-5]基本一致
由此,證明線上的OOM一確實(shí)是由于FD數(shù)目過多導(dǎo)致的OOM岖是,推斷驗(yàn)證成功.
OOM一的定位與解決:
?最終原因是App中使用的長連接庫再某些時候會有瞬時發(fā)出大量http請求的bug(導(dǎo)致FD數(shù)激增)帮毁,已修復(fù)
線上OOM二驗(yàn)證
?集中在華為系統(tǒng)的OOM二崩潰時收集到的信息樣例如下实苞,(收集的樣例中包含的devicemodel有VKY-AL00,TRT-AL00A烈疚,BLN-AL20黔牵,BLN-AL10,DLI-AL10爷肝,TRT-TL10猾浦,WAS-AL00等):
- /proc/pid/status中threads記錄全部到達(dá)上限:Threads: 500
- 崩潰時日志信息與圖[3-6]基本一致
推斷驗(yàn)證成功,即線程數(shù)受限導(dǎo)致創(chuàng)建線程時clone failed導(dǎo)致了線上的OOM二灯抛。
OOM二的定位與解決:
?關(guān)于App業(yè)務(wù)代碼中的問題還在定位修復(fù)中
3.4 解釋
下面從代碼分析本文描述的OOM是怎么發(fā)生的金赦,首先線程創(chuàng)建的簡易版流程圖如下所示:
上圖中,線程創(chuàng)建大概有兩個關(guān)鍵的步驟:
- 第一列中的創(chuàng)建線程私有的結(jié)構(gòu)體JNIENV(JNI執(zhí)行環(huán)境对嚼,用于C層調(diào)用Java層代碼)
- 第二列中的調(diào)用posix C庫的函數(shù)pthread_create進(jìn)行線程創(chuàng)建工作
下面對流程圖中關(guān)鍵節(jié)點(diǎn)(圖中有標(biāo)號的)進(jìn)行說明:
- 圖中節(jié)點(diǎn)①夹抗, /art/runtime/thread.cc中的函數(shù)Thread:CreateNativeThread部分節(jié)選代碼如下:
std::string msg(child_jni_env_ext.get() == nullptr ?
"Could not allocate JNI Env" :
StringPrintf("pthread_create (%s stack) failed: %s", PrettySize(stack_size).c_str(), strerror(pthread_create_result)));
ScopedObjectAccess soa(env);
soa.Self()->ThrowOutOfMemoryError(msg.c_str());
????????圖3-9 Thread:CreateNativeThread節(jié)選
可知:
- JNIENV創(chuàng)建不成功時產(chǎn)生OOM的錯誤信息為"Could not allocate JNI Env",與文中OOM一一致
- pthread_create失敗時拋出OOM的錯誤信息為"pthread_create (%s stack) failed: %s".其中詳細(xì)的錯誤信息由pthread_create的返回值(錯誤碼)給出.錯誤碼與錯誤描述的對應(yīng)關(guān)系可以參見bionic/libc/include/sys/_errdefs.h中的定義.文中OOM二的具體錯誤信息為"Out of memory"纵竖,就說明pthread_create的返回值為12.
...
__BIONIC_ERRDEF( EAGAIN , 11, "Try again" )
__BIONIC_ERRDEF( ENOMEM , 12, "Out of memory" )
...
__BIONIC_ERRDEF( EMFILE , 24, "Too many open files" )
...
????????圖3-10 系統(tǒng)錯誤定義_errdefs.h
- 圖中節(jié)點(diǎn)②和③是創(chuàng)建JNIENV過程的關(guān)鍵節(jié)點(diǎn)漠烧,節(jié)點(diǎn)②/art/runtime/mem_map.cc中函數(shù)MemMap:MapAnonymous的作用是為JNIENV結(jié)構(gòu)體中Indirect_Reference_table(C層用于存儲JNI局部/全局變量)申請內(nèi)存,申請內(nèi)存的方法是節(jié)點(diǎn)③所示的函數(shù)ashmem_create_region(創(chuàng)建一塊ashmen匿名共享內(nèi)存,并返回一個文件描述符).節(jié)點(diǎn)②代碼節(jié)選如下:
if (fd.get() == -1) {
*error_msg = StringPrintf("ashmem_create_region failed for '%s': %s", name, strerror(errno));
return nullptr;
}
????????圖3-11 MemMap:MapAnonymous節(jié)選
?我們線上的OOM一的錯誤信息"ashmem_create_region failed for 'indirect ref table': Too many open files"靡砌,與此處打印的信息吻合."Too many open files"的錯誤描述說明此處的errno(系統(tǒng)全局錯誤標(biāo)識)為24(見圖[3-10]系統(tǒng)錯誤定義_errdefs.h).
?由此看出我們線上的OOM一是由于文件描述符數(shù)目已滿已脓,ashmem_create_region無法返回新的FD而導(dǎo)致的.
- 圖中節(jié)點(diǎn)④和⑤是調(diào)用C庫創(chuàng)建線程時的環(huán)節(jié),創(chuàng)建線程首先調(diào)用__allocate_thread函數(shù)申請線程私有的棧內(nèi)存(stack)等通殃,然后調(diào)用clone方法進(jìn)行線程創(chuàng)建.申請stack采用的時mmap的方式度液,節(jié)點(diǎn)⑤代碼節(jié)選如下:
if (space == MAP_FAILED) {
__libc_format_log(ANDROID_LOG_WARN,
"libc",
"pthread_create failed: couldn't allocate %zu-bytes mapped space: %s",
mmap_size, strerror(errno));
return NULL;
}
????????圖3-12 __create_thread_mapped_space節(jié)選
?打印的錯誤信息與圖[3-7]中進(jìn)程邏輯地址占滿導(dǎo)致的OOM錯誤信息吻合,圖[3-7]中錯誤信息" Try again"說明系統(tǒng)全局錯誤標(biāo)識errno為11(見圖[3-10]系統(tǒng)錯誤定義_errdefs.h).
?pthread_create過程中画舌,節(jié)點(diǎn)4相關(guān)代碼如下:
int rc = clone(__pthread_start, child_stack, flags, thread, &(thread->tid), tls, &(thread->tid));
if (rc == -1) {
int clone_errno = errno;
// We don't have to unlock the mutex at all because clone(2) failed so there's no child waiting to
// be unblocked, but we're about to unmap the memory the mutex is stored in, so this serves as a
// reminder that you can't rewrite this function to use a ScopedPthreadMutexLocker.
pthread_mutex_unlock(&thread->startup_handshake_mutex);
if (thread->mmap_size != 0) {
munmap(thread->attr.stack_base, thread->mmap_size);
}
__libc_format_log(ANDROID_LOG_WARN, "libc", "pthread_create failed: clone failed: %s", strerror(errno));
return clone_errno;
}
????????圖3-13 pthread_create節(jié)選
?此處輸出的錯誤日志"pthread_create failed: clone failed: %s"與我們線上發(fā)現(xiàn)的OOM二吻合恨诱,圖[3-6]中的錯誤描述" Out of memory"說明系統(tǒng)全局錯誤標(biāo)識errno為12(見圖[3-10]系統(tǒng)錯誤定義_errdefs.h).
?由此線上的OOM二就是由于線程數(shù)的限制而在節(jié)點(diǎn)5 clone失敗導(dǎo)致OOM.
四. 結(jié)論及監(jiān)控
4.1 導(dǎo)致OOM發(fā)生的原因
綜上,可以導(dǎo)致OOM的原因有以下幾種:
-
文件描述符(fd)數(shù)目超限骗炉,即proc/pid/fd下文件數(shù)目突破/proc/pid/limits中的限制照宝。可能的發(fā)生場景有:
短時間內(nèi)大量請求導(dǎo)致socket的fd數(shù)激增句葵,大量(重復(fù))打開文件等 -
線程數(shù)超限厕鹃,即proc/pid/status中記錄的線程數(shù)(threads項(xiàng))突破/proc/sys/kernel/threads-max中規(guī)定的最大線程數(shù)≌д桑可能的發(fā)生場景有:
app內(nèi)多線程使用不合理剂碴,如多個不共享線程池的OKhttpclient等等 - 傳統(tǒng)的java堆內(nèi)存超限,即申請堆內(nèi)存大小超過了 Runtime.getRuntime().maxMemory()
- (低概率)32為系統(tǒng)進(jìn)程邏輯空間被占滿導(dǎo)致OOM.
- 其他
4.2 監(jiān)控措施
可以利用linux的inotify機(jī)制進(jìn)行監(jiān)控:
- watch /proc/pid/fd來監(jiān)控app打開文件的情況,
- watch /proc/pid/task來監(jiān)控線程使用情況.
五. Demo
POC(Proof of concept) 代碼參見:https://github.com/piece-the-world/OOMDemo