面试时的那些坑之内存泄漏和内存溢出

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/chenxiaoping1993/article/details/78921671

这也是我们面试时经常碰到的问题:
简单来说 内存溢出就是内存不够了。
内存泄漏就是有些对象我们不需要,但由于存在一些引用关系,GC无法回收。

要分析这两者,首先需要知道Android 系统是怎么去分配内存的。
我们需要确定这样几个概念

  1. Android中,内存的分配是以进程为最小单位。正常情况下,一个应用就是一个进程。
  2. 每一个进程得到的内存分为 堆,栈,和静态区。
  3. 堆存储创建的对象(new),栈存储对象的引用和基本类型(int ,float,double等)。
  4. 栈中存储的信息在存储之前就确定了存在时间的长度。(存在长度取决于它是全局变量,还是局部变量)
  5. 进程被分配的内存大小是可以变化的,但是有上限,到达上限进程就会被杀死。
  6. 我们常说的GC(Android 垃圾回收机制)只针对堆(即只是操纵堆中的对象)

我们再回过头说内存溢出的概念:
内存溢出,就是内存不够了。那为什么内存不够了,因为概念 5 ,我们被分配到的内存是有限的。怎么解决呢?
1、减少对象的内存占用
2、对象的重复使用
1.1 使用更加轻量级的数据结构,使用 Arraymap/SparseArray 来替换 HashMap;
1.2 避免在 Android 中使用枚举
1.3 减少Bitmap 的内存占用
1.3.1 合适的缩放比例
1.3.2 合适的编码格式
1.3.3 使用更小的图片
1.3.4 矢量图的使用
2.1 ListView 等的优化,例如使用 ViewHolder
2.2 对象池的使用
2.3 复用系统自带的资源
2.4 使用 inBitmap
2.5 避免在 onDraw() 方法中执行对象的创建
2.6 StringBuider 代替 + 的使用

内存泄漏呢,内存泄漏大多是因为我们写代码时不注意造成的。
我们每创建一个对象,这个对象就会被放到一个以 GCroot为根节点的树结构上。
垃圾回收的机制就是 回收那些存在于内存中,但根节点不可达的对象。
内存泄漏就是存在这样的一些对象,存在于内存中,根节点可达,但是我们不需要。
为什么会出现内存泄漏,我们应该怎么去避免它?
1、注意Activity 泄漏:
内部类引用导致Activity 的泄漏(Handler)
Activity 的 Context 传入其它类(SingleTask 单例模式)
没有及时回收临时的 Bitmap
监听器没有注销(Listener)
缓存容器中的对象泄漏
Cursor,receiver 等对象使用后没有关闭。
2、 内存使用策略优化
综合考虑设备内存的阈值和其它因素设计合适的内存大小
onLowMemory() 和 onTrimMemory() 的使用
谨慎使用 static 对象
Service 和 IntentService
谨慎使用抽象编程
谨慎使用第三方的库

面试的时候,也许会问到每一项中具体的内容,网上很多,在这儿就不赘述了。

那内存泄漏和内存溢出的发生会导致什么后果呢?
内存溢出(oom),进程被系统杀死。
内存泄漏,首先导致手机掉帧,卡顿,最后进程被系统杀死。
那我们继续想,为什么会出现卡顿呢?
不管是手机,还是电脑显示器,再或者gif 动画,视频。都是由一帧一帧(fps)(一张一张)的图片构成的。人眼看每秒 40–60fps 之间不觉的卡顿,小于40fps/s 就会感觉出卡顿。
Android 手机是每秒 60fps,大概 16毫秒一帧。
这 16毫秒内,cpu 要计算界面中显示的控件的大小,位置等,计算完毕之后交给 gpu 进行渲染,呈现到大家面前。那如果在 16 毫秒内无法完成,则会出现掉帧的现象,人会感觉到卡顿。
我们知道了卡顿的原理,继续说为什么会卡顿。因为内存泄漏,使得内存的使用量越来越大,这个时候会越来越频繁的触发 GC,而 GC 的操作是需要占用 cpu 的,也就会占用我们的 16 毫秒,也就会出现卡顿了。
那我们继续发问,什么时候才会触发 GC 呢?
有两种方式,一种是人为的进行调用,System.gc();人为的调用只会增加触发GC的概率,不一定会立即触发。
另外一种就是系统自己触发。
我们进程的堆空间,又被系统细分为 年轻态,老年态和持久态。新创建的对象放到年轻态,过一段时间之后如果没有被回收就放到老年态,以此类推,呆的越久,该对象因内存 不足而被回收的优先级就越低(就是越不容易被回收)。
当对象的总大小达到某一临界点的时候,系统就会触发GC。具体临界点是啥,众说风云,咱也不需要去深究这个东西,所以仅知道会触发GC 就可以了。

那我们遇到内存泄漏和内存溢出要怎么去找出泄漏的地方,怎么去解决呢?
建议大家看一下这个 Android性能优化的方方面面

展开阅读全文

没有更多推荐了,返回首页