Andoird优化(二)_内存优化_点进来看看不会后悔的

96
影响身边的人
0.1 2016.07.30 23:36* 字数 3126
内存管理

性能优化总纲:

大概会花一个月左右的时间出7-8个专题来分享一下在工作和学习中积累下来的Android性能优化经验
希望大家会持续关注。

现在是专题二:内存优化

但这也仅仅是为大家提供一些思路与较为全面的总结,算不上什么,希望有错误或问题在下面评论。

最后完结以后会将思维导图与优化框架整理出来,请期待。
如果程序会运行着崩溃、或者突然被系统杀死,那你就该继续往下看。

Anroid优化(二)_内存优化2.png

这是这章的思维导图,不过压缩严重,下面是样图,原图和源文件在最下方链接。还是值得下载的。

样图

题记

应用的生存期绝大部分时间都用于处理内存中的数据,虽然我们大多数人都意识到在手机上要尽可能少使用内存,但并非所有人都认识到了内存使用对性能的影响。所以,下面我们来讨论一下。


一、谈谈移动设备中的内存

  • 无论分配给应用多少内存,它都不会满足。

  • 移动设备和传统的电脑有两个很大的差异;

  • 物理内存大小

  • 虚拟内存交换能力

  • 要在一定设备上使用尽可能少的内存,既是经验也是常识。

    • 好处:
      减少碰到oom异常的风险
      提升性能
  • 性能取决于以下三个因素( 我们会在下面讲解)

    • CPU如何操纵特定的数据类型
    • 数据和指令需要占用多少存储空间

二、采用合适的数据类型

使用long比short和int慢
同样,只使用double及混用float和double,比只用float慢。

注意:由于并不是所有指令的执行时间都相同,再加上cpu很复杂,所以并不能推测出具体的时间。 short数组排序远比其他类型数组快

原因: short使用计数排序,算法复杂度是线性的
而int和long使用快速排序算法

处理64位类型(long或double)比处理32位类型慢

总的来说,
就是:

1、处理大量数据时,使用可以满足要求的最小数据类型

2、避免类型转换。尽量保持类型一致,尽可能在计算中使用单一类型。

3、如果有必要取得更好的性能,推倒重来,但要认真处理。


三、你需要知道的访问内存

1、操纵较大类型的数据代价较高,因为用到了指令较多。 直观的来说,指令越多性能越差,CPU需要做很多额外的工作

2、此外、代码和数据都驻留在内存中,访问内存本身也有开销。 因为访问内存会产生一些开销,CPU会把最近访问的内容缓存起来,无论是内存读还是写。

3、CPU通常使用两级缓存或者三级缓存:

  • 一级缓存
  • 二级缓存
  • 三级缓存(一般用于服务器机或游戏机器)

4、当数据或指令在缓存中找不到时,就是缓存未命中。这是需要从内存中读取数据或指令。
缓存未命中几种情况:

  • 指令缓存读未命中
  • 数据缓存读未命中
  • 写未命中

注意:第一种缓存未命中最关键,因为CPU要一直等到从内存中读出指令,才可以继续执行。

另外:现代CPU都能够自动预取内存,为了避免或者只说是限制了缓存未命中情况的发生。


四、通过垃圾收集管理内存

1、Java的一个非常重要的优点是垃圾收集

  • 原理: 不再使用的对象内存会被垃圾收集器释放(回收)。
  • 注意:还是会出现内存泄露的情况。
  • 垃圾收集器会帮你管理内存,它做的不仅仅是释放不用的内存。 
    

2、内存泄漏:

  • 只有当某个对象不再被引用时,它的内存才会被回收,当该被释放的对象引用仍然存在时就会发生内存泄漏。
  • 一个典型例子就是,由于屏幕旋转,整个Activity对象会有泄露 很严重!因为Activity对象占用相当多内存。

3、 避免内存泄漏方案。(大多数只能用来分析,并不会告诉你是否内存泄漏)

  • DDMS视图里面的Heap与Tracker 可以跟踪内存使用和分配情况。 AS里面的monitor 有内存、网络、等四个视图
  • StrictMode类 会将检测到的违规操作,将结果写到日志中。 只能用来分析,并不会告诉你是否内存泄漏
  • OneAPM 用过,并且也去面试过,很不错。

五、通过Java中的引用来更好的管理

1、内存释放是垃圾收集器的一个重要的特性,在垃圾收集器中它的作用比在内存管理系统中大得多。

2、Java定义了4中类型的引用

  • 强(Strong):
    其实就是普通的创建对象,保持无用对象的强引用可能会导致内存泄漏
  • 软(Soft):
    其实软引用和弱引用在本质上是类似的,软引用适用于缓存,它可以自动删除缓存中的条目
  • 弱(Weak)         
            保障下次垃圾回收时基本会收走
    
  • 虚(Phantom)
    几乎很少用到

3、当需要缓存或映射时,你不必实现类似的内存管理系统。精心规划引用后,大部分工作可以放心地交给垃圾收集器完成。

4、 垃圾收集
垃圾收集可能会再不定的时间触发,你几乎无法控制它的时机。
但是有时,你可以通过System.gc( );提醒一下Android,
虽然如此,垃圾收集机制发生时间最终时间是不由你确定的。

5、 垃圾收集发生在应用的主线程,所以:

  • 很可能降低响应速度和性能。
  • 在及时游戏中会出现丢帧,因为有太多时间花在垃圾收集上。
  • Andorid2.3有了转机,垃圾收集工作转移到了一个单独的线程。比以前的Android版本好太多了

六、通过系统的API可以了解、管理内存

1、 Android定义了几个API,你可以用他们来了解系统中还剩多少可用内存和用了多少内存

  • ActivityManager的:
    getMomoryInfo()
    getMomoryClass()
    getLargeMeoryClass()
  • Debug的
    dumpHprofData()
    getNativeHeapAllocatedSize()
    getNativeHeapSize()

提示:
在应用的manifest文件中把android:largeHeap设为true,就可以让应用使用更大的堆。


七、当内存少的时候可以这样处理

ComponentCallbacks接口定义了API onLowMomory( ),它对所有应用组> 件都是相同的。当它被调用时,组件基本会被要求释放那些并不会用到的内存。
可以被释放的内容:

  • 缓存或缓存条目(如使用强引用的LruCache)
  • 可以再次按需生成的位图对象
  • 不可见的布局对象
  • 数据库对象

八、通过5R法来对ANDROID内存进行优化:

1.Reckon(计算)

首先需要知道你的app所消耗内存的情况,知己知彼才能百战不殆
通过上文提到的工具进行查看消耗,这里再给大家推荐一个工具
Memory Analysis Tool(MAT):
可以转换成饼图和表格,直观、好用。

2.Reduce(减少)

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

例如:
Bitmap:

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

图片显示:

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

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

图片大小:

使用BitmapFactory.Options设置inSampleSize, 这样做可以减少对系统资源的要求。

BitmapFactory.Options bitmapFactoryOptions = new BitmapFactory.Options();  
 bitmapFactoryOptions.inJustDecodeBounds = true;  
 bitmapFactoryOptions.inSampleSize = 2;  
 // 这里一定要将其设置回false,因为之前我们将其设置成了true    
 // 设置inJustDecodeBounds为true后,decodeFile并不分配空间,即,BitmapFactory解码出来的Bitmap为Null,但可计算出原始图片的长度和宽度    
 options.inJustDecodeBounds = false;  
 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没有透明度属性),如下:

public static BitmapreadBitMap(Contextcontext, intresId) {  
     BitmapFactory.Optionsopt = newBitmapFactory.Options();  
     opt.inPreferredConfig = Bitmap.Config.RGB_565;  
     opt.inPurgeable = true;  
     opt.inInputShareable = true;  
     //获取资源图片   
     InputStream is = context.getResources().openRawResource(resId);  
     return BitmapFactory.decodeStream(is, null, opt);  
 } 

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

bitmap.recycle();  
  bitmap = null;  

捕获异常:

Bitmap bitmap = null;  
 try {  
    // 实例化Bitmap  
    bitmap = BitmapFactory.decodeFile(path);  
 } catch (OutOfMemoryError e) {  
     // 捕获OutOfMemoryError,避免直接崩溃  
}  
 if (bitmap == null) {  
     // 如果实例化失败 返回默认的Bitmap对象  
     return defaultBitmapMap;  
 } 


修改引用

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

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

3.Reuse(重用)

核心思路就是将已经存在的内存资源重新使用而避免去创建新的,最典型的使用就是缓存(Cache)和池(Pool)。

4.Recycle(回收)

Thread(线程)回收:

Thread t = new Thread() {  
     public void run() {  
         while (true) {  
             try {  
                 Thread.sleep(1000);  
                 System.out.println("thread is running...");  
             } catch (InterruptedException e) {  
               
             }  
        }  
     }  
 };  
 t.start();  
 t = null;  
 System.gc();  

Cursor(游标)回收:

@Override    
protected void onDestroy() {          
     if (mAdapter != null && mAdapter.getCurosr() != null) {    
         mAdapter.getCursor().close();    
    }    
     super.onDestroy();     
 }


还有接收器、流等等。

5.Review(检查)

Code Review(代码检查):

Code Review主要检查代码中存在的一些不合理或可以改进优化的地方,

UI Review(视图检查):

Android对于视图中控件的布局渲染等会消耗很多的资源和内存,所以这部分也是我们需要注意的。
减少视图层级:
减少视图层级可以有效的减少内存消耗,因为视图是一个树形结构,每次刷新和渲染都会遍历一次。

hierarchyviewer

想要减少视图层级首先就需要知道视图层级,所以下面介绍一个SDK中自带的一个非常好用的工具hierarchyviewer。

你可以在下面的地址找到它:your sdk path\sdk\tools


总结:

删除对象应该仔细考虑,因为重新创建是需要开销的。

如果没有释放出足够的内存可能会导致Android系统更激进的行为(如杀死进程)。

如果应用进程被杀掉了,用户下次使用又要从头开始。因此,应用不仅要表现出色,也要释放尽可能多的资源。 代码中推迟初始化是一个好的方式。

内存在嵌入式设备上是稀缺资源。尽管今天的手机和平板电脑的内存越来越多, 但这些设备也在运行越来越复杂的系统和应用。有效的使用内存, 不仅可以使应用在旧设备上运行时占用较少的内存, 还可以让程序跑的更快。请记住,应用对内存的需求是无止境的。

链接点下方,如果不能用及时留言,莫名被删过
链接:http://pan.baidu.com/s/1hsK2Co0 密码:abcs

技术
Web note ad 1