内存优化实践(一)浅谈内存优化

本系列文章,主要是总结我对Android开发过程中内存优化的理解,很多东西都是平常的习惯和一些细节问题,重在剖析优化的原理,养成一种良好的代码习惯。

概述

既然谈优化,就绕不开Android三个内存相关的经典问题:

  • OOM
  • 内存泄漏
  • 频繁GC卡顿

导致这三个问题的原因:

OOM

App在启动时会从系统分配一个默认的堆内存,同时拥有一个堆内存最大值(可以动态申请这个大小),这个Max Heap Size的大小,决定了软件运行时可以申请的最大运行内存。App软件内存分配是个不断创建和GC回收的过程,就像一个水池拥有注入和排出水的通道,当注入过快,排出不足时,水池满了溢出,Out of Memory,即我们常说的OOM。

内存泄漏

当我们在代码中创建对象,会申请内存空间,同时包含一个对象的引用,当我们长时间不使用该引用时,JVM GC操作时会根据这个引用去释放内存。但是,对象的回收可能有点差错,如果这个对象A被另一个线程B所引用,当我们不再使用A,可A却处于B的hold状态,那么我们每次创建的A都得不到回收,这个时候就会发生内存泄漏了。

频繁GC卡顿

上面说了,App的堆内存有最大值,是有限的,那么如果我们频繁的创建,当运行内存不断上升,为了维持App的运行,GC回收也会频繁操作,软件运行资源有些,必然导致卡顿问题。

JAVA的GC机制,非常的复杂和精辟,不可一言概论之,在看过许多blog之后,给出一点自己的总结。

简述JVM GC

我们都知道Java语言非常的方便,不像C语言,申请和释放内存都是自己操作,java有虚拟机帮忙。Android 的每个应用程序都会使用一个专有的Dalvik虚拟机实例来运行,即使内存泄漏也只是kill当前App.

Java虚拟机有一套完整的GC方案,只是简单理解的话就是,它维持着一个对象关系树,当开始GC操作时,它会从GC Roots开始扫描整个Object Tree,当发现某个无法从Tree中引用到的对象时,便将其回收

GC Roots分类举例:

  • Class类
  • Alive Thread
  • 线程stack上的对象,如方法或者局部变量
  • JNI活动对象
  • System Class Loader

Java中的引用关系

java中有四种对象引用关系,分别是:强引用StrongRefernce、软引用SoftReference、弱引用WeakReference、虚引用PhantomReference,这四种引用关系分别对应的效果:

StrongRefernce

通过new创建的对象,如Object obj = new Object();,强引用不会被垃圾回收器回收和销毁,即是OOM,所以这也容易造成我们接下来会分析的**《非静态内部类持有对象导致的内存泄漏问题》**

SoftReference

软引用可以被垃圾回收器回收,但它的生命周期要强于弱引用,但GC回收发生时,只有在内存空间不足时才会回收它

WeakReference

弱引用的生命周期短,可以被GC回收,但GC回收发生时,扫描到弱引用便会被垃圾回收和销毁掉

PhantomReference

虚引用任何时候都可以被GC回收,它不会影响对象的垃圾回收机制,它只有一个构造函数,因此只能配合ReferenceQueue一起使用,用于记录对象回收的过程

	PhantomReference(T referent, ReferenceQueue<? super T> q)

关于ReferenceQueue

他的作用主要用于记录引用是否被回收,除了强引用其他的引用方式得构造函数中都包含了ReferenceQueue参数。当调用引用的get()方法返回null时,我们的对象不一定已经回收掉了,可能正在进入回收流程中,而当对象被确认回收后,它的引用会被添加到ReferenceQueue中。

Felix obj = new Felix();
ReferenceQueue<Felix> rQueue = new ReferenceQueue<Felix>();
WeakReference<Felix> weakR = new WeakReference<Felix>(obj,rQueue);

总结

看完Android引用和回收机制,我们对于代码中内存问题的原因也有一定认识,当时现实中内存泄漏或者溢出的问题,总是不经意间,在我之后一些列的文章中,会对不同场景的代码问题进行分析和解决,一起来关注吧!

猜你喜欢

转载自blog.csdn.net/sslinp/article/details/84787843
今日推荐