内存屏障(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线程之间通讯的桥梁