android内存优化大全_中

转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持!java


写在最前:面试

本文的思路主要借鉴了2014年AnDevCon开发者大会的一个演讲PPT,加上把网上搜集的各类内存零散知识点进行汇总、挑选、简化后整理而成。缓存

因此我将本文定义为一个工具类的文章,若是你在ANDROID开发中遇到关于内存问题,或者立刻要参加面试,或者就是单纯的学习或复习一下内存相关知识,都欢迎阅读。(本文最后我会尽可能列出所参考的文章)。app


OOM:工具


内存泄露能够引起不少的问题:性能

1.程序卡顿,响应速度慢(内存占用高时JVM虚拟机会频繁触发GC)学习

2.莫名消失(当你的程序所占内存越大,它在后台的时候就越可能被干掉。反以内存占用越小,在后台存在的时间就越长)优化

3.直接崩溃(OutOfMemoryError)spa


ANDROID内存面临的问题:操作系统

1.有限的堆内存,原始只有16M

2.内存大小消耗等根据设备,操做系统等级,屏幕尺寸的不一样而不一样

3.程序不能直接控制

4.支持后台多任务处理(multitasking)

5.运行在虚拟机之上


5R:

本文主要经过以下的5R方法来对ANDROID内存进行优化:


1.Reckon(计算)

首先须要知道你的app所消耗内存的状况,知己知彼才能百战不殆

2.Reduce(减小)

消耗更少的资源

3.Reuse(重用)

当第一次使用完之后,尽可能给其余的使用

5.Recycle(回收)

回收资源

4.Review(检查)

回顾检查你的程序,看看设计或代码有什么不合理的地方。



Reckon:


关于内存简介,和Reckon(内存计算)的内容请看上一篇文章:ANDROID内存优化(大汇总——上)



Reduce :


Reduce的意思就是减小,直接减小内存的使用是最有效的优化方式。

下面来看看有哪些方法能够减小内存使用:


Bitmap
Bitmap是内存消耗大户,绝大多数的OOM崩溃都是在操做Bitmap时产生的,下面来看看几个处理图片的方法:


图片显示:

咱们须要根据需求去加载图片的大小。

例如在列表中仅用于预览时加载缩略图(thumbnails )。

只有当用户点击具体条目想看详细信息的时候,这时另启动一个fragment/activity/对话框等等,去显示整个图片


图片大小:

直接使用ImageView显示bitmap会占用较多资源,特别是图片较大的时候,可能致使崩溃。 
使用BitmapFactory.Options设置inSampleSize, 这样作能够减小对系统资源的要求。 
属性值inSampleSize表示缩略图大小为原始图片大小的几分之一,即若是这个值为2,则取出的缩略图的宽和高都是原始图片的1/2,图片大小就为原始大小的1/4。 

[java]  view plain copy print ?
  1. BitmapFactory.Options bitmapFactoryOptions = new BitmapFactory.Options();  
  2. bitmapFactoryOptions.inJustDecodeBounds = true;  
  3. bitmapFactoryOptions.inSampleSize = 2;  
  4. // 这里必定要将其设置回false,由于以前咱们将其设置成了true    
  5. // 设置inJustDecodeBounds为true后,decodeFile并不分配空间,即,BitmapFactory解码出来的Bitmap为Null,但可计算出原始图片的长度和宽度    
  6. options.inJustDecodeBounds = false;  
  7. Bitmap bmp = BitmapFactory.decodeFile(sourceBitmap, options);  


图片像素:

Android中图片有四种属性,分别是:
ALPHA_8:每一个像素占用1byte内存 
ARGB_4444:每一个像素占用2byte内存 
ARGB_8888:每一个像素占用4byte内存 (默认)
RGB_565:每一个像素占用2byte内存 

Android默认的颜色模式为ARGB_8888,这个颜色模式色彩最细腻,显示质量最高。但一样的,占用的内存也最大。 因此在对图片效果不是特别高的状况下使用RGB_565(565没有透明度属性),以下:
[java]  view plain copy print ?
  1. publicstaticBitmapreadBitMap(Contextcontext, intresId) {  
  2.     BitmapFactory.Optionsopt = newBitmapFactory.Options();  
  3.     opt.inPreferredConfig = Bitmap.Config.RGB_565;  
  4.     opt.inPurgeable = true;  
  5.     opt.inInputShareable = true;  
  6.     //获取资源图片   
  7.     InputStreamis = context.getResources().openRawResource(resId);  
  8.     returnBitmapFactory.decodeStream(is, null, opt);  
  9. }  

图片回收:

使用Bitmap事后,就须要及时的调用Bitmap.recycle()方法来释放Bitmap占用的内存空间,而不要等Android系统来进行释放。

下面是释放Bitmap的示例代码片断。

[java]  view plain copy print ?
  1. // 先判断是否已经回收  
  2. if(bitmap != null && !bitmap.isRecycled()){  
  3.     // 回收而且置为null  
  4.     bitmap.recycle();  
  5.     bitmap = null;  
  6. }  
  7. System.gc();  

捕获异常:

通过上面这些优化后还会存在报OOM的风险,因此下面须要一道最后的关卡——捕获OOM异常:

[java]  view plain copy print ?
  1. Bitmap bitmap = null;  
  2. try {  
  3.     // 实例化Bitmap  
  4.     bitmap = BitmapFactory.decodeFile(path);  
  5. catch (OutOfMemoryError e) {  
  6.     // 捕获OutOfMemoryError,避免直接崩溃  
  7. }  
  8. if (bitmap == null) {  
  9.     // 若是实例化失败 返回默认的Bitmap对象  
  10.     return defaultBitmapMap;  
  11. }  



修改对象引用类型:


引用类型:

引用分为四种级别,这四种级别由高到低依次为:强引用>软引用>弱引用>虚引用。

强引用(strong reference)
如:Object object=new Object(),object就是一个强引用了。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具备强引用的对象来解决内存不足问题。

软引用(SoftReference)
只有内存不够时才回收,经常使用于缓存;当内存达到一个阀值,GC就会去回收它;

弱引用(WeakReference)   

弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它 所管辖的内存区域的过程当中,一旦发现了只具备弱引用的对象,无论当前内存空间足够与否,都会回收它的内存。 


虚引用(PhantomReference)   

"虚引用"顾名思义,就是形同虚设,与其余几种引用都不一样,虚引用并不会决定对象的生命周期。若是一个对象仅持有虚引用,那么它就和没有任何引用同样,在任什么时候候均可能被垃圾回收。  


软引用和弱引用的应用实例:

注意:对于SoftReference(软引用)或者WeakReference(弱引用)的Bitmap缓存方案,如今已经不推荐使用了。自Android2.3版本(API Level 9)开始,垃圾回收器更着重于对软/弱引用的回收,因此下面的内容能够选择忽略。

在Android应用的开发中,为了防止内存溢出,在处理一些占用内存大并且声明周期较长的对象时候,能够尽可能应用软引用和弱引用技术。

下面以使用软引用为例来详细说明(弱引用的使用方式与软引用是相似的):

假设咱们的应用会用到大量的默认图片,并且这些图片不少地方会用到。若是每次都去读取图片,因为读取文件须要硬件操做,速度较慢,会致使性能较低。因此咱们考虑将图片缓存起来,须要的时候直接从内存中读取。可是,因为图片占用内存空间比较大,缓存不少图片须要不少的内存,就可能比较容易发生OutOfMemory异常。这时,咱们能够考虑使用软引用技术来避免这个问题发生。

首先定义一个HashMap,保存软引用对象。

[java]  view plain copy print ?
  1. private Map<String, SoftReference<Bitmap>> imageCache = new HashMap<String, SoftReference<Bitmap>>();  
再来定义一个方法,保存Bitmap的软引用到HashMap。

[java]  view plain copy print ?
  1. public void addBitmapToCache(String path) {  
  2.        // 强引用的Bitmap对象  
  3.        Bitmap bitmap = BitmapFactory.decodeFile(path);  
  4.        // 软引用的Bitmap对象  
  5.        SoftReference<Bitmap> softBitmap = new SoftReference<Bitmap>(bitmap);  
  6.        // 添加该对象到Map中使其缓存  
  7.        imageCache.put(path, softBitmap);  
  8.    }  
获取的时候,能够经过SoftReference的get()方法获得Bitmap对象。
[java]  view plain copy print ?
  1. public Bitmap getBitmapByPath(String path) {  
  2.         // 从缓存中取软引用的Bitmap对象  
  3.         SoftReference<Bitmap> softBitmap = imageCache.get(path);  
  4.         // 判断是否存在软引用  
  5.         if (softBitmap == null) {  
  6.             return null;  
  7.         }  
  8.         // 取出Bitmap对象,若是因为内存不足Bitmap被回收,将取得空  
  9.         Bitmap bitmap = softBitmap.get();  
  10.         return bitmap;  
  11.     }  
使用软引用之后,在OutOfMemory异常发生以前,这些缓存的图片资源的内存空间能够被释放掉的,从而避免内存达到上限,避免Crash发生。

须要注意的是,在垃圾回收器对这个Java对象回收前,SoftReference类所提供的get方法会返回Java对象的强引用,一旦垃圾线程回收该Java对象以后,get方法将返回null。因此在获取软引用对象的代码中,必定要判断是否为null,以避免出现NullPointerException异常致使应用崩溃。


到底何时使用软引用,何时使用弱引用呢?

我的认为,若是只是想避免OutOfMemory异常的发生,则可使用软引用。若是对于应用的性能更在乎,想尽快回收一些占用内存比较大的对象,则可使用弱引用。

还有就是能够根据对象是否常用来判断。若是该对象可能会常用的,就尽可能用软引用。若是该对象不被使用的可能性更大些,就能够用弱引用。

另外,和弱引用功能相似的是WeakHashMap。WeakHashMap对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的回收,回收之后,其条目从映射中有效地移除。WeakHashMap使用ReferenceQueue实现的这种机制。


其余小tips:



相关文章
相关标签/搜索