java oom

二、OOM問(wèn)題的可能原因


重點(diǎn)關(guān)注下面兩點(diǎn)

?? 堆內(nèi)存分配失敗時(shí)的OOM? ==?? /art/runtime/gc/heap.cc

?? 創(chuàng)建線程失敗時(shí)的OOM ? ? ==?? /art/runtime/thread.cc

三、OOM -- 堆內(nèi)存分配失敗

在source code中我們可以看到,當(dāng)堆內(nèi)存分配失敗時(shí),會(huì)拋出一些典型的log,如下代碼


在出現(xiàn)OOM問(wèn)題時(shí),logcat中應(yīng)該會(huì)看到類似下面的信息輸出

08-1911:34:53.8602802828028EAndroidRuntime:java.lang.OutOfMemoryError:Failedtoallocatea20971536byteallocationwith6147912free bytes and6003KB until OOM,target footprint134217728,growth limit134217728

上面這段logcat的大概解釋:想要去分配 20971536 bytes的heap memory,但時(shí)app剩余可用的free heap只有6147912 bytes,而且當(dāng)前app最大可分配的heap是134217728 bytes


堆內(nèi)存分配失敗的原因可以分兩種情況:

? ? ? 1. 超過(guò)APP進(jìn)程的heap內(nèi)存上限 與 2. 沒(méi)有足夠大小的連續(xù)地址空間

3.1 超過(guò)APP進(jìn)程的內(nèi)存上限

Android設(shè)備上java虛擬機(jī)對(duì)單個(gè)應(yīng)用的最大內(nèi)存分配做了約束,超出這個(gè)值就會(huì)OOM。由Runtime.getRuntime.MaxMemory()可以得到Android中每個(gè)進(jìn)程被系統(tǒng)分配的內(nèi)存上限,當(dāng)進(jìn)程占用內(nèi)存達(dá)到這個(gè)上限時(shí)就會(huì)發(fā)生OOM,這也是Android中最常見(jiàn)的OOM類型。

3.2 沒(méi)有足夠大小的連續(xù)地址空間

這種情況一般是進(jìn)程中存在大量的內(nèi)存碎片導(dǎo)致的,其堆棧信息會(huì)比第一種OOM堆棧多出一段類似如下格式的信息

:failed duetofragmentation(required continguous free “<<required_bytes<<“ bytesforanewbuffer where largest contiguous free ”<<largest_continuous_free_pages<<“ bytes)”

相關(guān)的代碼在art/runtime/gc/allocator/rosalloc.cc中,如下

voidRosAlloc::LogFragmentationAllocFailure(std::ostream&os,size_t failed_alloc_bytes){...if(required_bytes>largest_continuous_free_pages){os<<"; failed due to fragmentation ("<<"required contiguous free "<<required_bytes<<" bytes"<<new_buffer_msg<<", largest contiguous free "<<largest_continuous_free_pages<<" bytes"<<", total free pages "<<total_free<<" bytes"<<", space footprint "<<footprint_<<" bytes"<<", space max capacity "<<max_capacity_<<" bytes"<<")"<<std::endl;}}

這種場(chǎng)景比較難模擬,這里就不做演示了。


四、OOM -- 創(chuàng)建線程失敗

Android中線程(Thread)的創(chuàng)建及內(nèi)存分配過(guò)程分析可以參見(jiàn)如下這篇文章:https://blog.csdn.net/u011578734/article/details/109331764

線程創(chuàng)建會(huì)消耗大量的系統(tǒng)資源(例如內(nèi)存),創(chuàng)建過(guò)程涉及java層和native的處理。實(shí)質(zhì)工作是在native層完成的,相關(guān)代碼位于 /art/runtime/thread.cc



4.1 創(chuàng)建JNI Env 失敗

一般有兩種原因

1. FD溢出導(dǎo)致JNIEnv創(chuàng)建失敗了,一般logcat中可以看到信息?Too many open files ... Could not allocate JNI Env

當(dāng)進(jìn)程fd數(shù)(可以通過(guò) ls /proc/pid/fd | wc -l 獲得)突破 /proc/pid/limits中規(guī)定的Max open files時(shí),產(chǎn)生OOM

E/art:ashmem_create_region failedfor'indirect ref table':Toomanyopenfilesjava.lang.OutOfMemoryError:Couldnot allocate JNIEnvatjava.lang.Thread.nativeCreate(NativeMethod)atjava.lang.Thread.start(Thread.java:730)

2. 虛擬內(nèi)存不足導(dǎo)致JNIEnv創(chuàng)建失敗了,一般logcat中可以看到信息?Could not allocate JNI Env: Failed anonymous mmap


4.2 創(chuàng)建線程失敗

一般有兩種原因

1. 虛擬內(nèi)存不足導(dǎo)致失敗,一般logcat中可以看到信息?mapped space: Out of memory? ... pthread_create (1040KB stack) failed: Out of memory

native層通過(guò)FixStackSize設(shè)置線程棧大小,默認(rèn)情況下,線程棧所需內(nèi)存總大小 = 1M + 8k + 8k,即為1040k。



4.3 debug技巧

對(duì)于FD的限制

可以執(zhí)行?cat /proc/pid/limits來(lái)查看Max open files 最大打開(kāi)的文件數(shù)量

可以執(zhí)行?ls /proc/pid/fd | wc -l來(lái)查看進(jìn)程打開(kāi)的文件數(shù)量

對(duì)于線程數(shù)量的限制

可以執(zhí)行cat /proc/sys/kernel/threads-max?查看系統(tǒng)最多可以創(chuàng)建多少線程

可以執(zhí)行echo 3000 > /proc/sys/kernel/threads-max修改這個(gè)值,做測(cè)試

查看系統(tǒng)當(dāng)前的線程數(shù)?top -H

對(duì)于虛擬內(nèi)存使用情況

可以執(zhí)行?cat /proc/pid/status | grep Vm查看VmSize及VmPeak

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容