Android leak内存,GitHub - jin870132/memoryleakdemo: 安卓内存泄露几种常见形式及解决方案...
安卓?jī)?nèi)存泄露幾種常見形式及解決方案
一.前言
1.內(nèi)存溢出與內(nèi)存泄露
內(nèi)存溢出(oom),是指程序在申請(qǐng)內(nèi)存時(shí),沒有足夠的內(nèi)存空間供其使用,出現(xiàn)oom;比如申請(qǐng)了一個(gè)integer,但給它存了long才能存下的數(shù),那就是內(nèi)存溢出。
內(nèi)存泄露 (memory leak),是指程序在申請(qǐng)內(nèi)存后,無(wú)法釋放已申請(qǐng)的內(nèi)存空間,一次內(nèi)存泄露危害可以忽略,但內(nèi)存泄露堆積后果很嚴(yán)重,無(wú)論多少內(nèi)存,遲早會(huì)被占光。
memory leak會(huì)最終會(huì)導(dǎo)致oom!
二.內(nèi)存泄露的幾種形式
1.匿名內(nèi)部類的使用
a.Thread內(nèi)存泄漏
這里最常見的形式就是使用new thread開啟一個(gè)子線程.
子線程會(huì)對(duì)當(dāng)前activity有一個(gè)隱式的強(qiáng)引用
當(dāng)activity退出時(shí)候,如果子線程還在運(yùn)行activity就不會(huì)釋放.
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檢測(cè)結(jié)果
解決辦法:
調(diào)用onDestroy后結(jié)束子線程
@Override
protected void onDestroy() {
super.onDestroy();
running = false;
}
b.Timer內(nèi)存泄露
這里既然thread使用有問題,那么我們用hander+Timer的形式可以嗎,我們來(lái)看看.
結(jié)果抱歉,使用Timer和Thread無(wú)論從原理還是結(jié)果上都與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檢測(cè)結(jié)果
解決辦法
@Override
protected void onDestroy() {
super.onDestroy();
timer.cancel();
}
2.純handler的錯(cuò)誤使用
如果僅使用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檢測(cè)結(jié)果
解決辦法
@Override
protected void onDestroy() {
super.onDestroy();
//移除當(dāng)前handler發(fā)送的請(qǐng)求
mhandler.removeCallbacksAndMessages(null);
}
3.context導(dǎo)致內(nèi)存泄露
做一個(gè)單例的ToastUtils來(lái)顯示toast是很多人會(huì)做的.你的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();
}
}
這樣寫其實(shí)有很大問題:
如果此時(shí)傳入的是 Activity 的 Context,當(dāng)這個(gè) Context 所對(duì)應(yīng)的 Activity 退出時(shí),由于該 Context 的引用被單例對(duì)象所持有,其生命周期等于整個(gè)應(yīng)用程序的生命周期,所以當(dāng)前 Activity退出時(shí)它的內(nèi)存并不會(huì)被回收,這就造成泄漏了。
LeakCanary檢測(cè)結(jié)果
解決辦法:
1.使用ApplicationContext代替Activity的Context
2.如果必須要Activity的Context請(qǐng)換種寫法吧,哈哈.
4.leackCannary使用
leackCannary使用其實(shí)非常簡(jiǎn)單
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.提醒
這里其實(shí)就已經(jīng)配置完成可以運(yùn)行使用了.
注意,當(dāng)你進(jìn)入一個(gè)activity再退出之后等個(gè)三五秒如果有溢出就會(huì)提示的.
4.講解
我們就拿這個(gè)例子來(lái)說
這個(gè)是告訴我們 ToastUtils下面有一個(gè)靜態(tài)成員變量toast
它引用了一個(gè)context
這個(gè)context是ContextErr這個(gè)activity的一個(gè)實(shí)例(instance)
它導(dǎo)致了內(nèi)存泄露.
5.源碼地址
總結(jié)
以上是生活随笔為你收集整理的Android leak内存,GitHub - jin870132/memoryleakdemo: 安卓内存泄露几种常见形式及解决方案...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java反编译工具_Java开发必会的反
- 下一篇: arraylist线程安全吗_Java中