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


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

2010-05-20 09:56:51|  分類: 默認分類 |  標簽:內存  溢出  android  oom  out  |字號 訂閱

 
 

        基於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. 
>
 
2012年02月04日  更新:

16M是怎么來的?算是實驗來的吧,每個機型不一樣,模擬器不同版本也不一樣,可以通過:
Runtime.getMaxMemory() 來查看。

long maxMemory()
Returns the maximum amount of memory that may be used by the virtual machine, or  Long.MAX_VALUE if there is no such limit.
        


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM