性能优化系列阅读
- Android性能优化
- 性能优化 - 消除卡顿
- 性能优化- 内存优化
- 性能分析工具 - TraceView
- Android性能分析工具
为什么内存优化?
在一个商业项目中,很有可能因为工程师的疏忽,导致代码质量不佳,影响到程序的运行效率,从而让用户感知到应用的卡顿、崩溃。而Android开发中,每个Android应用在手机上申请的内存空间都是有限的。虽然手机发展越来越快,可申请到的内存越来越大,但是也不能大手大脚,随便浪费应用可使用的内存空间。内存一旦不够时,你这个应用就会因为OOM(out of memory)而崩溃。因此,内存优化这一块内容,在开发应用时是非常重要的。
1. 内存优化的关键点—避免内存泄露
内存优化中非常关键的一点,就是避免内存泄露。因为内存泄露会严重的导致内存浪费,所以避免内存泄露,是内存优化中必不可少的。
2. java中的四种引用类型
java引用类型不是指像int、char等这些基本的数据类型。java中的引用类型有四种:强引用、软引用、弱引用、虚引用。这四种引用类型,它们关于对象的可及性是由强到弱的。
public class ReferenceDemo {
public static void main(String[] args) {
// 强引用:对象类型 对象的名字(实例) = 对象的构造方法;
String str = "abc"; // 常量池
// String str = new String("abc"); // 堆内存
// 软引用,当内存不足的时候,才会释放掉它引用的对象
SoftReference<String> softReference = new SoftReference<String>(str);
// 弱引用,只要系统产生了GC(垃圾回收),它引用的对象就会被释放掉
WeakReference<String> weakReference = new WeakReference<String>(str);
// 虚引用,实际用的不多,就是判断对象已被回收
// PhantomReference<String> phantomReference = new PhantomReference<String>(referent,q);
str = null;
System.out.println("强引用:" + str);
softReference.clear();
System.out.println("软引用:" + softReference.get());
// 通过GC,将String对象回收了,那你引用中的对象也会变成null,gc只回收堆内存
System.gc();
System.out.println("弱引用:" + weakReference.get());
}
}
2.1 强引用
最常见的强引用方式如下:
//强引用 对象类型 对象名 = new 对象构造方法();
//比如下列代码
String str = new String("abc");
在上述代码中,这个str对象就是强可及对象。强可及对象永远不会被GC回收。它宁愿被抛出OOM异常,也不会回收掉强可及对象。
清除强引用对象中的引用链如下:
String str = new String("abc");
//置空
str = null;
2.2 软应用
软引用方式如下:
//软引用SoftReference
SoftReference<String> softReference = new SoftReference<String>(str);
在上述代码中,这个str对象就是软可及对象。当系统内存不足时,软可及对象会被GC回收。
清除软引用对象中的引用链可以通过模拟系统内存不足来清除,也可以手动清除,手动清除如下:
SoftReference<String> softReference = new SoftReference<String>(str);
softReference.clear();
2.3 弱引用
弱引用方式如下:
//弱引用WeakReference
WeakReference<String> weakReference = new WeakReference<>(str);
在上述代码中,这个str对象就是弱可及对象。当每次GC时,弱可及对象就会被回收。
清除弱引用对象中的引用链可以通过手动调用gc代码来清除,如下:
WeakReference<String> weakReference = new WeakReference<>(str);
System.gc();
当然,也可以通过类似软引用,调用clear()方法也可以。
2.4 虚引用
虚引用方式如下:
//虚引用PhantomReference
PhantomReference phantomReference = new PhantomReference<>(arg0, arg1);
虚引用一般在代码中出现的频率极低,主要目的是为了检测对象是否已经被系统回收。它在一些用来检测内存是否泄漏的开源项目中使用到过,如LeakCanary。
2.5 补充
- 一个对象的可及性由最强的那个来决定。
- System.gc()方法只会回收堆内存中存放的对象。
String str = "abc";
//弱引用WeakReference
WeakReference<String> weakReference = new WeakReference<>(str);
System.gc();
像这样的代码,即使gc后,str对象仍然可以通过弱引用拿到。因为像”abc”这种,并没有存放在堆内 存中,它被存放在常量池里,所以gc不会去回收。
3. 内存泄露的原因
对无用对象的引用一直未被释放,就会导致内存泄露。如果对象已经用不到了,但是因为疏忽,导致代码中对该无用对象的引用一直没有被清除掉,就会造成内存泄露。
比如你按back键关掉了一个Activity,那么这个Activity页面就暂时没用了。但是某个后台任务如果一直持有着对该Activity对象的引用,这个时候就会导致内存泄露。
4. 检测内存泄露—LeakCanary
在全球最大的同性交友网站github中,有一个非常流行的开源项目LeakCanary,它能很方便的检测到当前开发的java项目中是否存在内存泄露。
5. LeakCanary的使用
5.1 官方使用文档描述
从LeakCanary的文档描述中,可以得知使用方式,简单翻译为如下步骤:
1.在你的项目中,找到moudle级别的build.gradle文件,并在dependencies标签里加上以下代码:
dependencies {
//... 你项目中以前声明的一些依赖
debugCompile