内存泄露
- 静态对象引用Context
//静态View导致内存泄露
private static TextView sTextView;
protected void onCreate(Bundle savedInstanceState) {
....
sTextView = (TextView) findViewById(R.id.tv_text);
....
}
从上面的代码不能直接看出View
对Context
的引用,但从View
构造器可知创建View
必须引用Context
(源码太复杂了没有找到相关代码,另外View
是依赖于Activity
的,其生命周期一般不会高于Activity
,声明为static是完全没有必要的这里只是用来说明静态对象引用可能会导致内存泄露
View(Context context)
View(Context context, AttributeSet attrs)
View(Context context, AttributeSet attrs, int defStyleAttr)
View(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
总结:
尽量减少静态对象的引用,如果一定要引用可以使用弱引用WeakReference
修改后的代码
private TextView sTextView;
....
- 内部类持有外部对象
//Handler.Callback内部类默认持有外部对象`MainActivity`
Handler mHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
return false;
}
});
....
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
System.out.println("post delayed may leak");
}
}, 50000);
....
上面代码中Handler.Callback
和Runnable
都是匿名内部类,非静态的内部类是默认持有外部对象的,所以Handler.Callback
和Runnable
都持有MainActivity
的引用。Handler
的对象是与当前线程绑定的,生命周期要比MainActivity
长,而Handler
通过Handler.Callback
和Runnable
间接持有MainActivity
使得MainActivity
无法通过GC清除(比如当屏幕旋转时会创建新的MainActivity
对象而原来的MainActivity
对象由于被Handler
间接引用无法通过GC清除从而出现内存泄露)
修改后的代码
Handler mHandler = new Handler(new HandlerCallback());
//静态内部类不持有外部对象
static class HandlerCallback implements Handler.Callback{
@Override
public boolean handleMessage(Message msg) {
return false;
}
}
....
mHandler.postDelayed(new MyRunnable(), 5000);
....
//静态内部类不持有外部对象
static class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("post delayed may leak");
}
}
内存抖动
短时建创建大量对象又迅速被销毁,频繁触发GC造成程序卡顿用户体验下降
....
for (int i = 0; i < 10000; i++) {
Rect rect = new Rect(0, 0, 100, 100);
System.out.println("-------: " + rect.width());
}
....
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//避免在onDraw等调用频繁的方法中创建对象
RectF rect = new RectF(0, 0, 100, 100);
Paint paint = new Paint();
....
避免在调用频繁的方法中创建对象
修改后的代码
private Rect rect = new Rect(0, 0, 100, 100);
....
for (int i = 0; i < 10000; i++) {
//避免短时间内创建大量对象产生内存抖动
// Rect rect = new Rect(0, 0, 100, 100);
System.out.println("-------: " + rect.width());
}
....
private RectF rect = new RectF(0, 0, 100, 100);
private Paint paint = new Paint();
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
....