前面一篇博客说到了,内存抖动的第二种情况,就是必须在短时间内创建对象,但是要控制数量;这个问题目前可以使用对象池的方法解决。

3)Object Pools

在程序里面经常会遇到的一个问题是短时间内创建大量的对象,导致内存紧张,从而触发GC导致性能问题。对于这个问题,我们可以使用对象池技术来解决它。通常对象池中的对象可能是bitmaps,views,paints等等。关于对象池的操作原理,不展开述说了,请看下面的图示:

使用对象池技术有很多好处,它可以避免内存抖动,提升性能,但是在使用的时候有一些内容是需要特别注意的。通常情况下,初始化的对象池里面都是空白的,当使用某个对象的时候先去对象池查询是否存在,如果不存在则创建这个对象然后加入对象池,但是我们也可以在程序刚启动的时候就事先为对象池填充一些即将要使用到的数据,这样可以在需要使用到这些对象的时候提供更快的首次加载速度,这种行为就叫做预分配。使用对象池也有不好的一面,程序员需要手动管理这些对象的分配与释放,所以我们需要慎重地使用这项技术,避免发生对象的内存泄漏。为了确保所有的对象能够正确被释放,我们需要保证加入对象池的对象和其他外部对象没有互相引用的关系。

其实对象池给笔者感觉与线程池相似,不同的是重心不同,线程池考虑的是运行速度提高(使用预先产生空闲线程的方式),对象池更侧重与数量(可能是分配对象内存时间是很短的,所以不需要预分配,导致对象池的预分配优势不明显)。

现在问题还没解决呢,关于解决内存抖动,对象池很好,但是仅仅是一个思想概念,没具体化。怎么实现呢,笔者推荐使用java的一个LinkedHashMap 这个类,与普通hashmap有不同,就是可以控制数量关于LinkedHashMap 更详细的信息,笔者已转载一篇感觉很棒的关于LinkedHashMap的博客,点击这里可查看

在这里Android已提供了一个类可以解决控制数量问题

LRU Cache 通过使用LinkedHashMap实现了LRU Cache (最近最少使用)算法,这是操作系统的一个算法,具体的自己百度很多,在这里不祥细说明。

LRUCache 的实现和使用,笔者也转载了一篇博客,感觉很全点击这里可查看,看了妈妈再也不用担心我的Android程序出现内存抖动了。

前面一篇结尾也提到了内存泄漏,但是一笔带过,这里接着前面内存泄漏的发现和定位,一般情况下,常见发生内存泄漏定位到的地方及解决方法如下:

1.集合类

集合类如果仅仅有添加元素的机制,而没有相应删除元素机制,这样就会造成内存被占用,如果这个类是全局性变量(比如类中有静态属性,全局性的map等即有静态引用或final一直指向它)。那么没有相应删除机制,很可能导致集合所占内存只增不减。  解决办法:在使用集合类时,增加删除元素机制,并适当调用减少集合所占内存。

2.单例模式

不正确使用单例模式,也会引起内存泄漏单例对象在初始化后将在JVM的整个生命周期存在(以静态变量方式),如果单例对象持有外部对象的引用,那么这个外部对象就会一直占用着内存,可能导致内存泄漏(取决于这外部对象是否一致有用)。   解决办法:单例对象中避免含有不是一直都有用的外部对象引用。

3.Android组件或特殊集合对象的使用

BraodcastReceiver ,ContentObserver,fileObserver,Cursor,Callback等在Activity onDestory或者某类生命周期结束之后一定要unregistere或者close掉,否则这个Activity类会被system强引用,不会被回收。不要直接对Activity进行直接引用作为成员变量,如果不得不这么做,调用private WeakPeferense mActivity 来做,相同的,对与Service等其他有自己生命周期的对象来说,直接引用都需要考虑是否会存在内存泄露的可能。

4.Handler

要知道,只要Handler 发送的Message尚未被处理,则该Message及发送它的Handler对象将被线程MessageQueue一直持有。由于Handler属于TLS(Thread Local Storage)变量,生命周期和Activity是不一致的。因此这种实现方式一般很难保证跟view或者Activity的生命周期保持一致,故很容易导致无法正确释放。如上所述,Handler使用要特别小心,否则很可能内存泄漏。   解决办法:在view 或者Activity生命周期结束前,确保Handler已没有未处理的消息(特别是延时消息)。

5.Thread 内存泄漏

线程也是造成内存泄露的一个重要源头,线程产生内存泄露的主要原因在于线程生命周期不可控,比如线程是Activity的内部类,则线程对象中保存了Activity的一个引用,当线程的run函数耗时较长没有结束时,线程对象是不会被销毁的,因此它所引用的老的Activity就出现了内存泄漏问题。解决办法:1.简化线程run函数执行的任务,使他在Activity生命周期结束前,任务运行完。2.为Thread增加撤销机制,当Activity生命周期结束时,将Thread的耗时任务撤销(笔者推荐这种)。

6.一些不良代码造成的内存压力

有些代码并不造成内存泄漏,但是他们是对没使用的内存没进行有效及时的释放,或是没有有效的利用已有的对象而是频繁的申请新内存。

(1) Bitmap 没调用recycle()

Bitmap 对象在不使用时,我们应该先调用recycle()释放内存,然后才置空,因为加载bitmap对象的内存空间,一部分是java的,一部分是c的(因为Bitmap分配的底层是通过jni调用的,Android的Bitmap底层是使用skia图形库实现,skia是用c实现的)。这个recycle()函数就是针对c部分的内存释放。

(2)构造Adapter时,没有使用缓存的convertView。   解决办法:使用静态holdview的方式构造Adapter。

这样到这里内存抖动和内存泄漏的发现,定位以及解决方法以说明完毕。

Android App卡顿慢优化之解决内存抖动及内存泄漏的更多相关文章

  1. Android App解决卡顿慢之内存抖动及内存泄漏(发现和定位)

    内存抖动是指在短时间内有大量的对象被创建或者被回收的现象,内存抖动出现原因主要是频繁(很重要)在循环里创建对象(导致大量对象在短时间内被创建,由于新对象是要占用内存空间的而且是频繁,如果一次或者两次在 ...

  2. android中app卡顿优化问题

     所谓app卡顿原因就是在运行时出现了丢帧,还可能是UI线程被阻塞.首先来一下丢帧现象,android每16ms会对界面进行一次渲染,如果app的绘制.计算等超过了16ms那么只能等下一个16ms才能 ...

  3. 面试官:你的App卡顿过吗?你是如何监控的?

    一.故事开始 面试官:平时开发中有遇到卡顿问题吗?你一般是如何监控的? 来面试的小伙:额...没有遇到过卡顿问题,我平时写的代码质量比较高,不会出现卡顿. 面试官:... 这回答似乎没啥问题,但是如果 ...

  4. ART:Android 摆脱卡顿的希望?

    与 iOS 相比,Android 的用户体验有个相对糟糕的开始.在很长的时间里,界面一直丑小鸭,卡顿也是挥不去的痛.不过,在 Google 的全力推动,以及硬件厂商的响应下,Android 还是跨越各 ...

  5. ViewPager -- Fragment 切换卡顿 性能优化

    当ViewPager切换到当前的Fragment时,Fragment会加载布局并显示内容,如果用户这时快速切换ViewPager,即 Fragment需要加载UI内容,而又频繁地切换Fragment, ...

  6. mysql卡顿问题查找和解决方法

    mysql卡顿问题查找和解决方法 版权一.所遇问题        写在前边的废话:今天面试阿里的时候问到过类似问题,以前做调优的时候都是现查现用,缺乏总结,面试时答得也不好,今天趁此机会做一个梳理,知 ...

  7. [FMX] Android APP 启动黑屏优化补丁

    使用说明 *************************************************** Android APP 启动黑屏优化补丁 作者: Swish, YangYxd 201 ...

  8. Android中app卡顿原因分析示例

    在知乎回答了一个“为什么微博的app在iPhone比Android上流畅”的问题.后面部分是一个典型的动画卡顿的性能分析过程,因此帖在这里.有编程问题可以在这里交流.知乎链接. =========== ...

  9. Android 教你如何发现 APP 卡顿

    最近部门打算优化下 APP 在低端机上的卡顿情况,既然想优化,就必须获取卡顿情况,那么如何获取卡顿情况就是本文目的. 一般主线程过多的 UI 绘制.大量的 IO 操作或是大量的计算操作占用 CPU,导 ...

随机推荐

  1. iPhone8发布后那些搞笑Geek段子合辑 #精选搞笑GEEK段子

    这些段子能把人笑出猪叫声哈哈哈哈哈哈哈哈哈哈哈哈嗝 前方高能!请带好安全帽观看段子手们的表演   只能帮你们到这里了 加了半截刘海,怎么像和天猫合作的了? 杜蕾斯的追热点也很及时啊!十年如一日是啥意思 ...

  2. iOS开发技巧 - 使用和定制开关控件(UISwitch)

    1. 初始化加载到视图界面 (Swift) import UIKit class ViewController: UIViewController { // 1. create a property ...

  3. IPC's epoch 6 is less than the last promised epoch 7

    一.错误起因 Active NameNode日志出现异常IPC‘s epoch [X] is less than the last promised epoch [X+1],出现短期的双Active ...

  4. NetCore的控制台应用中搭建WebServer的方法

    一.新建NetCore控制台项目,并引入下列Nuget包: Microsoft.AspNetCore.StaticFiles.Microsoft.AspNetCore.Http.Microsoft.A ...

  5. excel自定义数据验证

    1. 判断必须为5位或者9位的数字 2. 自定义限制级别和提示消息

  6. tornado输出json

    只需要输出一个dict就自动会变成json http://www.tornadoweb.org/en/stable/web.html#tornado.web.RequestHandler.write

  7. java笔记整理

    Java 笔记整理 包含内容     Unix Java 基础, 数据库(Oracle jdbc Hibernate pl/sql), web, JSP, Struts, Ajax Spring, E ...

  8. vue 模板如何解析

    1.模板 一个最简答的模板: <div id="app"> {{ message }} </div> v-for模板: <ul id="ex ...

  9. C#匿名对象在其它方法体内怎么取到相应的值(不想建立对应的类并转化的情况下)?

    public object AnonymousObj() { ", Message = "OK", Data = new {...} } } public void Ot ...

  10. 索引全扫描(INDEX FULL SCAN)

    所谓的索引全扫描(INDEX FULL SCAN)就是指要扫描目标索引所有叶子块的所有索引行.这里需要注意的是,索引全扫描需要扫描目标索引的所有叶子块,但这并不意味着需要扫描该索引的所有分支块.在默认 ...