Android leak内存,GitHub - jin870132/memoryleakdemo: 安卓内存泄露几种常见形式及解决方案...
安卓內存泄露幾種常見形式及解決方案
一.前言
1.內存溢出與內存泄露
內存溢出(oom),是指程序在申請內存時,沒有足夠的內存空間供其使用,出現oom;比如申請了一個integer,但給它存了long才能存下的數,那就是內存溢出。
內存泄露 (memory leak),是指程序在申請內存后,無法釋放已申請的內存空間,一次內存泄露危害可以忽略,但內存泄露堆積后果很嚴重,無論多少內存,遲早會被占光。
memory leak會最終會導致oom!
二.內存泄露的幾種形式
1.匿名內部類的使用
a.Thread內存泄漏
這里最常見的形式就是使用new thread開啟一個子線程.
子線程會對當前activity有一個隱式的強引用
當activity退出時候,如果子線程還在運行activity就不會釋放.
running = true;
new Thread(new Runnable() {
@Override
public void run() {
while (running) {
SystemClock.sleep(1000);
runOnUiThread(new Runnable() {
@Override
public void run() {
SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String date = sDateFormat.format(new Date());
tv.setText(date);
}
});
}
}
}).start();
LeakCanary檢測結果
解決辦法:
調用onDestroy后結束子線程
@Override
protected void onDestroy() {
super.onDestroy();
running = false;
}
b.Timer內存泄露
這里既然thread使用有問題,那么我們用hander+Timer的形式可以嗎,我們來看看.
結果抱歉,使用Timer和Thread無論從原理還是結果上都與handler一樣.
public class HandlerAndTimerErr extends AppCompatActivity {
Handler mhandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
tv.setText(msg.obj.toString());
}
};
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_thread_err);
tv = (TextView) findViewById(R.id.tv);
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String date = sDateFormat.format(new Date());
Message message = new Message();
message.obj=date;
mhandler.sendMessage(message);
}
}, 1, 1000);
}
}
LeakCanary檢測結果
解決辦法
@Override
protected void onDestroy() {
super.onDestroy();
timer.cancel();
}
2.純handler的錯誤使用
如果僅使用handler還可以這樣寫
public class HandlerErr extends AppCompatActivity {
Handler mhandler = new Handler();
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_thread_err);
tv = (TextView) findViewById(R.id.tv);
mhandler.postDelayed(new Runnable() {
@Override
public void run() {
SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String date = sDateFormat.format(new Date());
tv.setText(date);
mhandler.postDelayed(this,1000);
}
},1000);
}
}
LeakCanary檢測結果
解決辦法
@Override
protected void onDestroy() {
super.onDestroy();
//移除當前handler發送的請求
mhandler.removeCallbacksAndMessages(null);
}
3.context導致內存泄露
做一個單例的ToastUtils來顯示toast是很多人會做的.你的ToastUtils是否這么寫的?
public class ToastUtils {
private static Toast toast;
public static void ShowToast(Context context, String text){
if (toast==null) {
toast = Toast.makeText(context, text, Toast.LENGTH_LONG);
}else{
toast.setText(text);
}
toast.show();
}
}
這樣寫其實有很大問題:
如果此時傳入的是 Activity 的 Context,當這個 Context 所對應的 Activity 退出時,由于該 Context 的引用被單例對象所持有,其生命周期等于整個應用程序的生命周期,所以當前 Activity退出時它的內存并不會被回收,這就造成泄漏了。
LeakCanary檢測結果
解決辦法:
1.使用ApplicationContext代替Activity的Context
2.如果必須要Activity的Context請換種寫法吧,哈哈.
4.leackCannary使用
leackCannary使用其實非常簡單
githup鏈接: https://github.com/square/leakcanary
1.首先在你的build.gradle添加引用:
dependencies {
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.1'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1'
testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1'
}
2.在你的application中初始化
LeakCanary.install(this);
3.提醒
這里其實就已經配置完成可以運行使用了.
注意,當你進入一個activity再退出之后等個三五秒如果有溢出就會提示的.
4.講解
我們就拿這個例子來說
這個是告訴我們 ToastUtils下面有一個靜態成員變量toast
它引用了一個context
這個context是ContextErr這個activity的一個實例(instance)
它導致了內存泄露.
5.源碼地址
總結
以上是生活随笔為你收集整理的Android leak内存,GitHub - jin870132/memoryleakdemo: 安卓内存泄露几种常见形式及解决方案...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java反编译工具_Java开发必会的反
- 下一篇: android app性能优化_Andr