内存抖动产生的原因
内存抖动是由于短时间内有大量对象进出新生区导致的,它伴随着频繁的GC。
gc会大量占用ui线程和cpu资源,会导致app整体卡顿。内存频繁的分配与回收,(分配速度大于回收速度时)最终会产生OOM。
内存回收算法
1、标记清除算法Mark-Sweep
2、复制算法Copying
3、标记压缩算法Mark-Compact
4、分代收集算法
Permanent和垃圾回收没什么关系,主要用来存放类,方法信息,也能作为常量沲使用,不同VM不同实现,有些没这个区
- Serial串行收集器
- ParNew 收集器
- Parallel Scavenge收集器
吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)。
- Serial Old收集器
- Parallel Old收集器
- CMS 收集器
CMS采用"标记-清理"算法实现以获取最短回收停顿时间为目标的收集器
初始标记:标记一下GC Roots能直接关联到的对象
并发标记:进行GC Roots Tracing 的过程
重新标记:是为了修正并发标记期间因用户程序继续运行而导致标记产品变动的那一部分对象的标记记录
并发清除:清除不能到达GC Roots的对象
重置线程:更新之前使用过的数据
内存抖动的实例
public class MainActivity extends AppCompatActivity {
private static Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// 创造内存抖动
for (int index = 0; index <= 100; index++) {
String arg[] = new String[10000];
}
mHandler.sendEmptyMessageDelayed(0, 1000);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacksAndMessages(null);
}
public void onMemoryJitter(View view) {
mHandler.sendEmptyMessage(0);
}
}
如上代码所示,在点击按钮的时候,每隔一秒钟就创建一个String数组,里面存放10000个元素。我们频繁的这样创建会内存泄漏,就会导致系统GC回收内存。
内存抖动日志分析如下所示:
2020-05-15 21:00:24.643 6632-6647/com.wq.demo E/com.wq.demo: GcSupervisor: GC congestion PID:6632 Freq:21/1.090s
2020-05-15 21:00:25.685 6632-6647/com.wq.demo E/com.wq.demo: GcSupervisor: GC congestion PID:6632 Freq:21/1.041s
2020-05-15 21:00:26.750 6632-6647/com.wq.demo E/com.wq.demo: GcSupervisor: GC congestion PID:6632 Freq:21/1.064s
2020-05-15 21:00:27.837 6632-6647/com.wq.demo E/com.wq.demo: GcSupervisor: GC congestion PID:6632 Freq:21/1.086s
2020-05-15 21:00:29.143 6632-6647/com.wq.demo E/com.wq.demo: GcSupervisor: GC congestion PID:6632 Freq:21/1.135s
2020-05-15 21:00:30.196 6632-6647/com.wq.demo E/com.wq.demo: GcSupervisor: GC congestion PID:6632 Freq:21/1.052s
2020-05-15 21:00:31.189 6632-6647/com.wq.demo E/com.wq.demo: GcSupervisor: GC congestion PID:6632 Freq:21/992.157ms
2020-05-15 21:00:32.147 6632-6647/com.wq.demo E/com.wq.demo: GcSupervisor: GC congestion PID:6632 Freq:21/957.596ms
2020-05-15 21:00:33.183 6632-6647/com.wq.demo E/com.wq.demo: GcSupervisor: GC congestion PID:6632 Freq:21/1.035s
android profile 效果图如下图
Memory 中
我们可以看到 上面的一个白色垃圾桶。说明在大量的执行gc操作。用了一会儿 手机就开始卡了
快速定位内存抖动
如上图所示,我们找到我们的应用就可以快速定位出代码中出现内存抖动的位置。
避免发生内存抖动的几点建议:
- 尽量避免在循环体内创建对象,应该把对象创建移到循环体外
- 注意自定义View的onDraw()方法会被频繁调用,所以在这里面不应该频繁的创建对象
- 当需要大量使用Bitmap的时候,试着把它们缓存在数组中实现复用。
- 对于能够复用的对象,同理可以使用对象池将它们缓存起来
总之,因为内存抖动是由于大量对象在短时间内被配置而引起的,所以我们要做的就是谨慎对待那些可能会大量创建对象的情况。