内存屏障(Memory Barrier)
内存泄漏
内存泄漏检查的工具:常见的Leakcanary
内存泄漏原因
长时间持有
Activity
或Fragment
对象导致的内存泄漏及时释放
Activity
或Frament
对象匿名内部类和非静态内部类导致的内存泄漏
避免匿名内部类和非静态内部类
WebView
持有Activity
对象导致的内存泄漏在使用
WebView
时,及时调用destroy
方法单例模式持有资源对象导致的内存泄漏
在单例模式中避免长时间持有资源对象
资源未关闭导致的内存泄漏
及时关闭资源对象
静态变量持有
Context
对象导致的内存泄漏避免静态变量持有
Context
对象Handler
持有外部类引用导致的内存泄漏避免
Handler
持有外部类引用Bitmap
占用大量内存导致的内存泄漏在使用
Bitmap
时,及时释放内存单例持有大量数据导致的内存泄漏
避免单例持有大量数据
不一定要用弱引用来避免内存泄露
WeakReference弱引用应该是修复内存泄露的最后手段。
(非常基础的方式)可以使用回调来避免内存泄露(AsyncTask)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26public class MainActivity extends Activity {
private MyAsyncTask task;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
task = new MyAsyncTask();
task.setListener(createListener());
task.execute();
}
protected void onDestroy() {
task.setListener(null);
super.onDestroy();
}
private MyAsyncTask.Listener createListener() {
return new MyAsyncTask.Listener() {
public void onSuccess(Object object) {
// adapt contents
}
};
}
}其中AsyncTask
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27class MyAsyncTask extends AsyncTask {
private Listener listener;
protected Object doInBackground(Object[] params) {
return doSomeStuff();
}
private Object doSomeStuff() {
//do something to get result
return new Object();
}
protected void onPostExecute(Object object) {
if (listener != null) {
listener.onSuccess(object);
}
}
public void setListener(Listener listener) {
this.listener = listener;
}
interface Listener {
void onSuccess(Object object);
}
}使用RxJava实现简单的例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36public class MainActivity extends Activity {
private Subscription subscription;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
subscription = Observable
.fromCallable(new Callable<Object>() {
public Object call() throws Exception {
return doSomeStuff();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Object>() {
public void call(Object o) {
// adapt contents
}
});
}
private Object doSomeStuff() {
//do something to get result
return new Object();
}
protected void onDestroy() {
subscription.unsubscribe();
super.onDestroy();
}
}避免内存泄露的一个很重要的守则是让内部类为静态类的。尤其是它们要做耗时的后台任务的时候。或者更好的方法是把这个类移到外面作为单独的类。
推荐两个Novoda的项目,是很好的学习资源
novoda/bonfire-firebase-sample
bonfire-firebase-sample – An app to discuss your favourite emojis. This is a sample app built with Firebase.github.com
spikes – Where ideas & concepts are born & incubatedgithub.com
内存抖动
概念:在循环中创建对象(比如onDraw中创建对象)内存达到临界值,会触发GC。频繁创建,频繁触发GC。从内存分析器(如AS–Run–Profiler(Memory Profiler))内看就是忽上忽下的波动,称作Memory Churn(内存抖动)。
内存抖动,可能会发展成内存泄漏
错误使用单例造成的内存泄露
单例持有Context
对象。构造方法中this.mContext=context.getApplicationContext()
赋值导致的
解决:改成this.mContext = context;
完整:
1 | public class LoginManager { |
静态集合类引起内存泄漏
Handler使用不当造成内存泄漏
handler是工作线程和UI线程之间通讯的桥梁