【Android】の基础——内存溢出&内存泄漏&UIL

一、内存泄露

内存泄漏:长生命周期的对象引用了短声明周期的对象,导致短生命周期的对象的工作在执行完后,无法在GC时被正常回收。

如何避免内存泄漏:

列举几个内存泄漏常见场景。

内部类引用导致Activity的泄漏。

内部类的优势是可以访问外部类,但内部类持有外部类实例的强引用往往导致内存泄漏。

Activity Context被传递到其他实例中。

这可能导致自身被引用而发生泄漏。所以要使用Application的Context。

临时Bitmap对象的及时回收。

注意临时Bitmap对象的及时回收(recycle掉),从而减轻GC的负担。

注意WebView的泄漏。

WebView的内部有一个类叫BrowserFrame,是Handler的子类,WebViewCoreThread通过它与Activity交互。如果Activity退出前,WebViewCoreThread处理了一个延时消息,就会造成内存泄漏。

注意Cursor、File是否及时关闭。

二、内存溢出

虚拟机为每个应用分配的内存是有限的,如果使用超过了这个限度就会发生内存溢出(OOM)。常见避免内存溢出的措施有:

使用更加轻量的数据结构。

比如SparseArray ArrayMap替代HashMap。
SparseArray通过两个数组,一个存储key(int型),另外一个存储value。二分查找法存储和读取数据。put数据的时候,按照key从小到大的顺序排列好。
ArrayMap原理跟SparseArray相似,它的数组mHash存储的是hash值,另一个数组mArray存mHash对应未知的key和value。HashMap在扩容时重新创建了对象,而ArrayMap对数组进行了复制。另外ArrayMap提供了数组收缩的功能,在clear或remove后,会重新收缩数组,释放空间。

SparseArray

1 SparseArray 内部使用双数组,分别存储 Key 和 Value,Key 是 int[],用于查找 Value 对应的 Index,来定位数据在 Value 中的位置。
2 使用二分查找来定位 Key 数组中对应值的位置,所以 Key 数组是有序的。
明了 SparseArray 内部使用二分查找,在 mKey 数组中定位 key 的位置。又因为需要支持二分查找,所以 mKey 数组内存储的数据,必须是有序的。所以在 put() 操作的时候,就需要通过数组插入的方式,来保证数据的有序。又因为使用了数组结构,在数据空间不够时,还需要采取动态扩容的方式,采用新旧数组复制的方式,增大数组的空间,这部分操作都封装在 GrowingArrayUtils 的 insert() 方法中。
3 使用数组就要面临删除数据时数据搬移的问题,所以引入了 DELETE 标记。
引入 DELETE 标识是为了减少删除数据时数据的搬移次数,而这必然带来了数组的「空洞」,为了解决这个问题,又需要在适当的时候触发 GC 操作,来回收 DELETE 标识。

Bitmap和ImageLoader框架

Bitmap是安卓中的图片,因为占用空间大,如果处理不好大图片或者大量图片,很容易造成OOM。
使用合适大小的图片,使用合适编码的Bitmap。
在加载时进行多级缓存。例如:Universal-Image-Loader框架。
###避免内存泄露
内存泄漏会导致内存很多空间被浪费。
###其他

  • 当界面不可见时释放内存、当内存紧张时释放内存
  • 避免在很小的ImageView上显示一张高分辨率的图片
  • 避免在Android里面使用Enum
  • 免在onDraw方法里面执行对象的创建:迅速增加内存的使用,而且很容易引起频繁的gc
  • 复用系统自带的资源
  • 注意在ListView ConvertView的复用
  • StringBuilder StringBuilder来替代频繁的“+
  • 谨慎使用large heap
  • 资源文件需要选择合适的文件夹进行存放
  • Try catch某些大内存分配的操作。在可能发生OOM的地方进行异常处理。

Universal-Image-Loader

这里写图片描述

工作流程:

①UI:请求数据,使用唯一的Key值索引Memory Cache中的Bitmap。
② 内存缓存:缓存搜索,如果能找到Key值对应的Bitmap,则返回数据。否则执行第三步。
③ 硬盘存储:使用唯一Key值对应的文件名,检索SDCard上的文件。
④ 如果有对应文件,使用BitmapFactory.decode*方法,解码Bitmap并返回数据,同时将数据写入缓存。如果没有对应文件,执行第五步。
⑤ 下载图片:启动异步线程,从数据源下载数据(Web)。
⑥ 若下载成功,将数据同时写入硬盘和缓存,并将Bitmap显示在UI中。

内存缓存LruMemoryCache:

LruMemoryCache使用LinkedHashMap来缓存数据。当LinkedHashMap的accessOrder==true时,每一次get或put操作都会将所操作项移动到链表的尾部(链表头被认为是最少使用的,链表尾被认为是最常使用的。),当内存不够时优先提出链表头部的数据。

磁盘缓存UnlimitedDiscCache:

它的fileNameGenerator通过对象的哈希值来命名,避免重复。

性能分析工具

LeakCanary
LeakCanary是一个开源类库,用以检测内存泄漏。
TraceView
TraceView可以让我们查看方法执行的时间。

三、内存抖动

内存抖动是由于短时间内有大量对象进出Young Generiation区导致的,它伴随着频繁的GC。

避免内存抖动

  • 尽量避免在循环体内创建对象,应该把对象创建移到循环体外。
  • 注意自定义View的onDraw()方法会被频繁调用,所以在这里面不应该频繁的创建对象。
  • 当需要大量使用Bitmap的时候,试着把它们缓存在数组中实现复用。
  • 对于能够复用的对象,同理可以使用对象池将它们缓存起来。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值