Android Out Of Memory(OOM) 的詳細研究

基於Android開發多媒體和遊戲應用時,可能會挺經常出現Out Of Memory 異常 ,顧名思義這個異常是說你的內存不夠用或者耗盡了。
        在Android中,一個Process 只能使用16M內存,如果超過了這個限制就會跳出這個異常。這樣就要求我們要時刻想着釋放資源。Java的回收工作是交給GC的,如何讓GC能及時的回收已經不是用的對象,這個裏面有很多技巧,大家可以google一下。
        因爲總內存的使用超過16M而導致OOM的情況,非常簡單,我就不繼續展開說。值得注意的是Bitmap在不用時,一定要recycle,不然OOM是非常容易出現的。
        本文想跟大家一起討論的是另一種情況:明明還有很多內存,但是發生OOM了。
        這種情況經常出現在生成Bitmap的時候。有興趣的可以試一下,在一個函數裏生成一個13m 的int數組。
        再該函數結束後,按理說這個int數組應該已經被釋放了,或者說可以釋放,這個13M的空間應該可以空出來,
        這個時候如果你繼續生成一個10M的int數組是沒有問題的,反而生成一個4M的Bitmap就會跳出OOM。這個就奇怪了,爲什麼10M的int夠空間,反而4M的Bitmap不夠呢?
       這個問題困擾很久,在網上,國外各大論壇搜索了很久,一般關於OOM的解釋和解決方法都是,如何讓GC儘快回收的代碼風格之類,並沒有實際的支出上述情況的根源。
       直到昨天在一個老外的blog上終於看到了這方面的解釋,我理解後歸納如下:
       在Android中:
       1.一個進程的內存可以由2個部分組成:java 使用內存 ,C 使用內存 ,這兩個內存的和必須小於16M,不然就會出現大家熟悉的OOM,這個就是第一種OOM的情況。
       2.更加奇怪的是這個:一旦內存分配給Java後,以後這塊內存即使釋放後,也只能給Java的使用,這個估計跟java虛擬機裏把內存分成好幾塊進行緩存的原因有關,反正C就別想用到這塊的內存了,所以如果Java突然佔用了一個大塊內存,即使很快釋放了:
        C能使用的內存 = 16M - Java某一瞬間佔用的最大內存。
       而Bitmap的生成是通過malloc進行內存分配的,佔用的是C的內存,這個也就說明了,上述的4MBitmap無法生成的原因,因爲在13M被Java用過後,剩下C能用的只有3M了。
 
下面是我參考的blog的所有內容:
內如如下:

> You might try to pre-allocate bitmap memory before launching the WebViews?It's not the WebView that's triggering the OOM, but some arbitrary otherpiece of code that needs memory that is not *there* anymore. Very often thisis happening when starting a new activity.

Ok, I see, I have to start dealing with automating my apology. 

There is one more, small thing that I can do. I also do some downloading andXML parsing in the background at times. This only takes Java Heap (<3MB),but maybe I should move that stuff to a separate process. This may lower thechances of an OOM. I'll think about it, but with all the added complexity ofinter process communication I am not sure I would want to go there.

Anyway, thanks for sharing your insights. That was very helpful.

 On Wed, Oct 7, 2009 at 10:48 PM, Tom Gibara <[EMAIL PROTECTED]> wrote: 
> I think it's better to add a couple more columns to the table to see the 
> picture (as I see it) more clearly:> JH = Java Heap
> JU = Memory actually used by Java
> NH = Native Heap 
> TU = Total memory Used = JU + NH
> TA = Total memory Allocated = JH + NH 
>
> (note I'm not distinguishing between native heap and native heap used 
> because it's not relevant here)
>
> The system requires TA (the process size as you called it) to not exceed 
> 16MB, the evolution is:
> JU JH NH TU TA 
> 1) 2 2 0 2 2
> 2) 4 4 0 4 4
> 3) 4 4 2 6 6 
> 4) 14 14 2 16 16
> 5) 4 14 2 6 16 
> 6) 4 14 4 10 18 *** OH NO! *** 
>
> The key is what happens between (4) and (5): GC reclaims 10MB (JU reduced> by 10MB) but the java heap doesn't shrink (JH stays at 14MB). This enlarged > java heap basically squeezes the maximum native heap allocation.
> The simplest approach is to try and ensure that your application maintains 
> a 'flatish' memory profile - no big spikes. You should do this anyway, since 
> it means that your application is being well behaved and won't force other 
> apps to be terminated just because your application needs a temporary shot> of memory (which will then remain as a glut until the application restarts).
>
> As you point out, WebViews are heavy on memory usage, and these might be 
> what's causing your memory usage to spike. I don't have any good suggestions 
> for a fix. You might try to pre-allocate bitmap memory before launching the 
> WebViews? It might work, but it may be complicated to do and could cause 
> OOMs when WebViews are instantiated - no way around that, your application
> is simply using too much memory at that point. 
>


來源:http://xiechengfa.iteye.com/blog/1055170


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章