Android OOM 引发的思考

一、Android 为何会出现OOM

因为Android系统的硬件资源是相当有限的,而且分配给一个应用的资源更为有限,尤其是内存。当 已使用的内存 + 新申请的内存 >  可分配的内存  的时候, 就会出现OOM。

 

如果想要获取App的内存使用情况,可以使用以下方法:

 final int M = 1024 * 1024;
 final Runtime runtime = Runtime.getRuntime(); 
 
 Log.i("Memory", "最大可用内存:" + runtime.maxMemory() / M + "M");
 Log.i("Memory", "当前可用内存:" + runtime.totalMemory() / M + "M");
 Log.i("Memory", "当前空闲内存:" + runtime.freeMemory() / M + "M");
 Log.i("Memory", "当前已使用内存:" + (runtime.totalMemory() - runtime.freeMemory()) / M + "M");

下面简单说一下每个函数的作用:

1)maxMemory()

该函数用于获取系统分配给JVM的最大可用内存(其实就是Java Heap),比如说使用以下Java命令启动Java程序:

java -Xms64m -Xmx1024m App01
那么,“-Xms64m”表示App01程序的初始内存为64M,“-Xmx1024m”表示App01最大可以使用的内存为1024M。当程序需要更新内存的时候,它最多可以增加到1024M,如果超过该值,即会报OOM错误。
 
 Android系统用的是Dalvik虚拟机,每个App的最大可用内存由系统指定(在/system/build.prop文件中有定义),如HTC E8手机的内存为2G,App的最大可用内存为192M。如果需要更大的内存的话,可以在AndroidManifest.xml中,给Application标签配置“android:largeHeap="true"”属性。这样的话,这台手机就可以最大获得512M内存了。
 
 你可能会很好奇,为什么有些APP(比如大型游戏)可以超过这个值?那是因为Java内存又分为Java Heap和Native Heap,Native Heap是不受该值约束的。像C/C++的内存都是在Native Heap中分配的。另外Bitmap是在Java Heap中分配的,我们开发过程中经常遇到由Bitmap引起的OOM,这就是一个例子。
 
2)totalMemory()
 
 该函数用于获取JVM当前可用内存。如果程序需要更多的内存,它最多不能超过maxMemory。
 如果设置为“-Xms1024m -Xmx1024m”,那么totalMemory=maxMamory。
 
3)freeMemory()
 
 该函数用于获取JVM可以被释放的内存。如果调用System.gc()的话,这部分内存将会被释放掉。
 若要准确地计算出当前程序所使用的内存,可以使用以下公式:
final long usedMemory = totalMemory() - freeMemory();

二、如何避免OOM

1. 使用合适的数据结构去存取数据

2. 尽量避免使用枚举

3. 修改应用内存的最大值

maxMemory限制了当前应用能够使用的最大内存值,而最大内存值基本上就决定了OOM出现的概率,目前能够修改最大内存值的方式就是,在Manifest里面添加Application标签:

android:largeHeap="true"

此时再测试一下,上面的代码,就基本上可以看到,最大内存值变大了。

具体的其他避免OOM的方式,目前不多赘述,写本文也是因为在正常使用时发现,即使使用避免OOM的方式时但还是无法避免OOM,只能尝试使用大堆来避免OOM。

思考&补充:

largeHeap的属性目前几乎所有的应用都开启这个设置了,所以为了保证App的稳定运行,是可以进行设置的。但不是系统有多少内存就可以申请多少,而是由dalvik.vm.heapsize限制。

作为程序员的我们应该努力减少内存的使用,尽量想回收和复用的方法,而不是想方设法增大内存。因为当内存很大的时候,每次gc的时间也会长一些,性能会下降的。

4. 使用NDK

Android 对Native Heap没有专门的使用限制。一般在开发App的时候的时候,推荐内存使用大户放在Native层。

5. 内存优化5R

  • Reduce : 抽稀策略 --> 例如:降低图片分辨率、重采样等。
  • ReUse:复用策略 ---> 例如:池化策略,避免重复创建对象,减少GC压力。
  • Recycle:回收策略 --->  例如:主动销毁,结束,避免内存泄漏/生命周期闭环。
  • Refactor : 重构策略 -->  例如: 更合适的数据结构/更合理的程序架构
  • ReValue:重审策略 ---> 例如:谨慎使用Large Heap/多进程/第三方框架   

 

posted @ 2018-03-26 19:57  灰色飘零  阅读(800)  评论(0编辑  收藏  举报