Android 内存溢出的几点解决方法

来源:互联网 发布:linux应用程序开发详解 编辑:程序博客网 时间:2024/05/16 18:58

前言:

   堆(HEAP)是VM中占用内存最多的部分,通常是动态分配的。堆的大小不是一成不变的,通常有一个分配机制来控制它的大小。比如初始的HEAP是4M大,当4M的空间被占用超过75%的时候,重新分配堆为8M大;当8M被占用超过75%,分配堆为16M大。倒过来,当16M的堆利用不足30%的时候,缩减它的大小为8M大。重新设置堆的大小,尤其是压缩,一般会涉及到内存的拷贝,所以变更堆的大小对效率有不良影响。

   

   我们知道,android程序内存一般限制在16M,当然也有24M的,而android程序内存被分为2部分:native和dalvik:dalvik就是我们平常说的java堆,我们创建的对象是在这里面分配的,而bitmap是直接在native上分配的,对于内存的限制是native+dalvik不能超过最大限制。注:一旦内存分配给Java后,以后这块内存纵然开释后,也只能给Java的施用,这个估计跟java虚拟机里把内存分成好几块进行缓存的原因有关(具体解释见下一段),反正C就别想用到这块的内存了,所以要是Java突然占用了一个大块内存,纵然很快开释了:C能施用的内存= 16M -Java某一瞬间占用的最大内存。而Bitmap的生成是通过malloc进行内存分配的,占用的是C的内存这个也就说明了,上面所说的4MBitmap无法生成的原因,因为在13M被Java用过后,剩下C能用的只有3M了。

   

   在Davilk中,给一个程序分配的内存根据机型厂商的不同,而不同,现在的大部分的是32M了,而在VM内部会把这些内存分成java使用的内存和Native使用的内存,它们之间是不能共享的,就是说当你的Native内存用完了,现在Java又有空闲的内存,这时Native会重新像VM申请,而不是直接使用java的。 

 

垃圾回收的几种情况:

GC_FOR_MALLOC means that the GC was triggered because there wasn'tenough memory left on the heap to perform an allocation. Might betriggered when new objects are beingcreated. 

GC_EXPLICIT means that the garbage collector has been explicitlyasked to collect, instead of being triggered by high water marks inthe heap. Happens all over the place, but most likely when a threadis being killed or when a binder communication is takendown. 

There are a few others as well: 

GC_CONCURRENT Triggered when the heap has reached a certain amountof objects to collect. 

GC_EXTERNAL_ALLOC means that the the VM is trying to reduce theamount of memory used for collectable objects, to make room formorenon-collectable. 

 

中文理解(Copy的)

  • GC_MALLOC, 内存分配失败时触发
  • GC_CONCURRENT,当分配的对象大小超过384K时触发
  • GC_EXPLICIT,对垃圾收集的显式调用(System.gc)
  • GC_EXTERNAL_ALLOC,外部内存分配失败时触发

 

freed 199K表示本次垃圾收集释放了199K的内存,

53% free3023K/6343K,其中6343K表示当前内存总量,3023K表示可用内存,53%表示可用内存占总内存的比例。

external 0K/0K,表示可用外部内存/外部内存总量
paused
2ms+2ms,第一个时间值表示markrootset的时间,第二个时间值表示第二次mark的时间。如果触发原因不是GC_CONCURRENT,这一行为单个时间值,表示垃圾收集的耗时时间。

调用垃圾回收的原因:
typedefenum{ 
    
   GC_FOR_MALLOC, 
    
   GC_CONCURRENT, 
    
   GC_EXPLICIT, 
    
   GC_EXTERNAL_ALLOC, 
    
   GC_HPROF_DUMP_HEAP 
}GcReason; 

 

垃圾回收调试信息解读(就是LogCat中那些GC信息):

Roughly speaking, the format is [Reason] [Amount Freed],[Heap Statistics], [External Memory Statistics], [PauseTime]

Reason

Robert/yuku already gave info on the meaning of these.

Amount Freed

E.g. freed 2125K

Self explanatory

Heap Statistics

E.g. 47% free 6214K/11719K

These numbers reflect conditions after the GC ran. The "47%free" and 6214K reflect the current heap usage. The 11719Krepresents the total heap size. From what I can tell, the heap cangrow/shrink, so you will not necessarily have an OutOfMemoryErrorif you hit this limit.

External Memory Statistics

E.g external 7142K/8400K

Note: This might only exist in pre-Honeycomb versions of Android(pre 3.0).

Before Honeycomb, bitmaps are allocated external to your VM(e.g. Bitmap.createBitmap() allocates the bitmap externally andonly allocates a few dozen bytes on your local heap). Otherexamples of external allocations are for java.nio.ByteBuffers.

Pause Time

If it""s a concurrent GC event, there will be two times listed.One is for a pause before the GC, one is for a pause when the GC ismostly done. E.g. paused 3ms+5ms

For non-concurrent GC events, there is only one pause time andit""s typically much bigger. E.g. paused 87ms

 

 

解决方法:

 

第一种:

android不同设备单个进程可用内存是不一样的,可以查看/system/build.prop文件。

# This is a high density device with more memory, so larger vmheaps for it.
dalvik.vm.heapsize=24m

上面heapsize参数表示单个进程可用的最大内存,单如果存在如下参数:

dalvik.vm.heapgrowthlimit=16m

largeheaplimit参数表示单个进程内存被限定在16m,即程序运行过程中实际只能使用16m内存,不过有一个办法可以解决,编辑AndroidManifest.xml中的Application节点,增加属性largeheap="true"参数.

第二种:

 VMRuntime.getRuntime().setMinimumHeapSize(NewSize);      (修改最小内存)话说没感觉有用。

第三种:

privatefinal static floatTARGET_HEAP_UTILIZATION =0.75f;

VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION);

 

这种是修改内存使用率,在系统GC的时候可以尽量提高回收的效率。

 

 

 

0 0