美文网首页ITAndroidAPP的优化
Andoird优化(二)_内存优化_点进来看看不会后悔的

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

作者: 影响身边的人 | 来源:发表于2016-07-30 23:36 被阅读5577次
    内存管理

    性能优化总纲:

    大概会花一个月左右的时间出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

    相关文章

      网友评论

      • 键盘男:冒昧问一句,笔者几年经验?
      • 捡淑:马克
      • 该账号已经被注销:StrictMode和Android Studio自带的Monitor无法检测内存泄露这两个是有问题的。以最常见的Activity泄露为例,如果你在日志里看到过at android.os.StrictMode.setClassInstanceLimit(StrictMode.java:1)并且你的Activity又是SingleInstance或者SingleTask的话,基本上是内存泄露没跑了。
        AS的Monitor在Dump Java Heap之后,有一个Analyzer Tasks的按钮,如果这个检测出来是内存泄露,基本上也是有问题的。
        影响身边的人:@实臧 能否加个好友,向你探讨一下,私信你了
        该账号已经被注销:@影响身边的人 。。内存泄露不是观察曲线是否平稳的,我本来是想写个文章的,然后想了一下过去一段时间看的文章大多是源于官方的文档和教程,虽然没有明显错误,但是也没有什么新意。上面那个Monitor检测和MAT的原理是一样的,都是看gc的回收路径,只不过两者在展示已有数据上区别很大。其实很多工具都是DDMS一套,AS一套,只不过在内存检测方面是MAT这个插件工具。这个工具本身是用来检测JAVA内存泄露的,只不过刚好可以用在Android开发上。
        影响身边的人:@实臧 谢谢指教,很感谢,不过Monitor可以检测是否稳定吧?通过不断的切换界面也是可以观察曲线是否平稳,通过这一点来判断内存泄露,我是这样理解的
      • 泽毛:很严谨,学习了,期待后面的文章!
      • Kulbear:想问一下思维图是哪个软件出的 收费吗?
        Kulbear:@影响身边的人 谢谢
        影响身边的人: @Kulbear
        Xmind 部分收费,也可以破解的
      • dea579f8285e:有没有全套的链接啊 希望能拜读下
        影响身边的人: @独领风骚 上一章发出来了😁,感兴趣去看看吧~
        影响身边的人: @独领风骚 哈哈 还没有写完呢
      • 紫豪:收了
      • AdventurerX:直接从二开始,没有优化一吗??
        影响身边的人:@AdventurerX 有的,在别的地方写了,整理中
      • 范尼斯特鲁伊呀:memory,单词貌似拼错了。文章很棒,学习了
        影响身边的人:@范尼斯特鲁伊呀 哈哈 谢谢 我再检查一下
      • 影响身边的人:自己占坑

      本文标题:Andoird优化(二)_内存优化_点进来看看不会后悔的

      本文链接:https://www.haomeiwen.com/subject/yietsttx.html