引用类型
- 强引用(StrongReference): 只要被持有, 就不会被GC回收
- 软引用(SoftReference): 只有在内存空间不足时,才会被回收; 可以用来做内存缓存
- 弱引用(WeakReference): 不管内存是否足够,一旦GC发现弱引用对象,都会被回收
- 虚引用(PhantomReference): 任何时候都有可能被GC回收
常见内存泄漏
内存泄漏是指new出来的对象,无法被GC回收, 或者在对象在该被回收时,还被其他对象持有, 无法被回收;
一般来说, 主要是由持有Object的对象, 和Object的生命周期不一样导致; 持有Object的对象会比Object本身生命周期长, 从而导致Object无法被释放;
比如, 单例持有其他对象, 消息队列持有其他对象;
1. 单例持有不该持有的对象
单例生命周期和应用是一样长的, 持有其他对象造成无法释放;
2. 非静态的内部类和匿名内部类
非静态内部类和匿名内部类都会持有外部类的引用, 如果不注意, 容易造成外部类
3. Handler造成的内存泄漏
- 当Handler有延迟任务时, 消息队列会中的Message会持有对Handler的引用, 而Hander由持有对外部类的潜在引用;
解决办法:
1、可以把Handler类放在单独的类文件中,或者使用静态内部类便可以避免泄露;
2、如果想在Handler内部去调用所在的Activity,那么可以在handler内部使用弱引用的方式去指向所在Activity.使用Static + WeakReference的方式来达到断开Handler与Activity之间存在引用关系的目的。 - HandlerThread造成内存泄漏; 由于Looper是一个死循环, HandlerThread任务执行完成之后, 不会自动销毁, 要手动调用quit方法结束
4. 监听器未反注册
一般我们会向系统服务注册监听器, 用于在部分情况下回调我们的方法, 此时系统就会持有我们的对象, 如果没有反注册, 造成被持有的对象无法释放
5. IO, Cursor, TypedArray等未关闭回收
内存抖动
内存抖动是指在段时间内创建了大量对象, 从而造成内存紧张, 频繁的触发GC;
eg. 在for循环中创建大量的临时对象; 在View.onDraw方法中创建对象
解决办法:
- 尽量减少在频繁调用的方法中创建大量临时对象
- 使用对象池; eg. 系统的MotionEvent, Message等都采用的是对象池; 系统V4包中也提供了工具类
Pool
供App快速实现对象池