说到性能优化,就不得不提下内存泄漏了,内存泄漏发生的原因以及解决办法你是否都已了解呢?看看今天的三问:
内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放
,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。
简单点说,手机给我们的应用提供了一定大小的堆内存
,在不断创建对象的过程中,也在不断的GC
(java的垃圾回收机制),所以内存正常情况下会保持一个平稳的值。但是出现内存泄漏就会导致某个实例,比如Activity的实例,应用被某个地方引用到了,不能正常释放,从而导致内存占用越来越大
,这就是内存泄漏。
主要有四类情况
:
1)集合类泄漏
集合类添加元素后,仍引用着集合元素对象,导致该集合中的元素对象无法被回收,从而导致内存泄露。
static List<Object> mList = new ArrayList<>();
for (int i = 0; i < 100; i++) {
Object obj = new Object();
mList.add(obj);
obj = null;
}
解决办法就是把集合也释放掉。
mList.clear();
mList = null;
2)单例/静态变量造成的内存泄漏
单例模式具有其静态特性
,它的生命周期等于应用程序的生命周期,正是因为这一点,往往很容易造成内存泄漏。
public class SingleInstance {
private static SingleInstance mInstance;
private Context mContext;
private SingleInstance(Context context){
this.mContext = context;
}
public static SingleInstance newInstance(Context context){
if(mInstance == null){
mInstance = new SingleInstance(context);
}
return sInstance;
}
}
比如这个单例模式,如果我们调用newInstance
方法时候把Activity的context
传进去,那么就是生命周期长的持有了生命周期短的引用,造成了内存泄漏。要修改的话把context改成context.getApplicationContext()
即可。
3)匿名内部类/非静态内部类
非静态内部类他会持有他外部类的强引用,所以就有可能导致非静态内部类的生命周期可能比外部类更长,容易造成内存泄漏,最常见的就是Handler
。
public class TestActivity extends Activity {
private TextView mText;
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
mHandler. sendEmptyMessageDelayed(0, 100000);
}
怎么修改呢?改成静态内部类,然后弱引用方式修饰外部类
public class TestActivity extends Activity {
private TextView mText;
private MyHandler myHandler = new MyHandler(TestActivity.this);
private MyThread myThread = new MyThread();
private static class MyHandler extends Handler {
WeakReference<TestActivity> weakReference;
MyHandler(TestActivity testActivity) {
this.weakReference = new WeakReference<TestActivity>(testActivity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
weakReference.get().mText.setText("do someThing");
}
}
@Override
protected void onDestroy() {
super.onDestroy();
myHandler.removeCallbacksAndMessages(null);
}
4)资源未关闭造成的内存泄漏
比如:
unregisterReceiver()
stopSelf()
1、使用工具,比如Memory Profiler
,可以查看app的内存实时情况,捕获堆转储,就生成了一个内存快照,hprof
文件。通过查看文件,可以看到哪些类发生了内存泄漏。
2、使用库,比较出名的就是LeakCanary
,导入库,然后运行后,就可以发现app内的内存泄漏情况。
这里说下LeakCanary
的原理:
ActivityLifecycleCallbacks
和FragmentLifeCycleCallbacks
监听Activity和Fragment的生命周期。ReferenceQueue
,通过该弱引用是否被加入ReferenceQueue就可以判断该对象是否被回收。hprof
文件,从而找出类之前的引用关系。https://juejin.im/post/6844903641032163336