Android中使用Thread造成記憶體洩露的分析和解決
Thread 記憶體洩露
執行緒也是造成記憶體洩露的一個重要的源頭。執行緒產生記憶體洩露的主要原因在於執行緒生命週期的不可控。
看一下下面是否存在問題
public class ThreadActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new MyThread().start();
}
private class MyThread extends Thread {
@Override
public void run() {
super.run();
dosomthing();
}
}
private void dosomthing(){
}
}
這段程式碼很平常也很簡單,是我們經常使用的形式。
真的沒有問題嗎
我們思考一個問題:假設MyThread的run函式是一個很費時的操作,當我們開啟該執行緒後,將裝置的橫屏變為了豎屏,
一般情況下當螢幕轉換時會重新建立Activity,按照我們的想法,老的Activity應該會被銷燬才對,然而事實上並非如此。
由於我們的執行緒是Activity的內部類,所以MyThread中儲存了Activity的一個引用,當MyThread的run函式沒有結束時,
MyThread是不會被銷燬的,因此它所引用的老的Activity也不會被銷燬,因此就出現了記憶體洩露的問題。
這種執行緒導致的記憶體洩露問題應該如何解決呢?
- 將執行緒的內部類,改為靜態內部類。
- 線上程內部採用弱引用儲存Context引用。
程式碼如下:
public class ThreadAvoidActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new MyThread(this).start();
}
private void dosomthing() {
}
private static class MyThread extends Thread {
WeakReference<ThreadAvoidActivity> mThreadActivityRef;
public MyThread(ThreadAvoidActivity activity) {
mThreadActivityRef = new WeakReference<ThreadAvoidActivity>(
activity);
}
@Override
public void run() {
super.run();
if (mThreadActivityRef == null)
return;
if (mThreadActivityRef.get() != null)
mThreadActivityRef.get().dosomthing();
// dosomthing
}
}
}
上面的兩個步驟其實是切換兩個物件的雙向強引用連結
靜態內部類:切斷Activity 對於 MyThread的強引用。
弱引用: 切斷MyThread對於Activity 的強引用。
AsynTask 內部類會如何呢?
有些人喜歡用Android提供的AsyncTask,但事實上AsyncTask的問題更加嚴重,
Thread只有在run函式不結束時才出現這種記憶體洩露問題,然而AsyncTask內部的實現機制是運用了ThreadPoolExcutor,
該類產生的Thread物件的生命週期是不確定的,是應用程式無法控制的,
因此如果AsyncTask作為Activity的內部類,就更容易出現記憶體洩露的問題。
在看android聯絡人2.3原始碼的時候看到一個類WeakAsyncTask, 內部用到了WeakReference軟引用, 這樣可以解決記憶體洩露的問題; 其實給AysncTask加上static, 靜態的內部類不會持有對外部類的引用, 就能夠解決問題, 只不過這樣如果AysncTask的方法用到的成員變數都需要加上static;
WeakReference和AsyncTask的美妙結合
為了避免開發者在UI執行緒上做耗時操作,Android提供了不少非同步API,其中之一就是AsyncTask。而對於某些頻繁運算元據庫的應用(例如,Phonebook)而言,需要一種非同步的並且低耗資源的(低耗是兩個方面的事情,要麼是你佔有的多點,但是能快速釋放;要麼是你本身就佔有的少。這兩種都可以保證其它應用有資源可用)元件。所以,那就來個WeakAsyncTask吧,唔,美妙的產物,既保證佔有資源的快速釋放,又保證操作是非同步進行。
那為什麼不是soft reference呢?
這個,來看看weak和soft兩者的區別:
* A SoftReference should be cleared and enqueued as late as possible, that is, in case the VM is in danger of running out of memory.
* A WeakReference may be cleared and enqueued as soon as is known to be weakly-referenced.
下面是WeakAsyncTask的原始碼:
public abstract class WeakAsyncTask<Params, Progress, Result, WeakTarget>
extends AsyncTask<Params, Progress, Result> {
protected WeakReference<WeakTarget> mTarget;
public WeakAsyncTask(WeakTarget target) {
mTarget = new WeakReference<WeakTarget>(target);
}
@Override
protected final void onPreExecute() {
final WeakTarget target = mTarget.get();
if (target != null) {
this.onPreExecute(target);
}
}
@Override
protected final Result doInBackground(Params... params) {
final WeakTarget target = mTarget.get();
if (target != null) {
return this.doInBackground(target, params);
} else {
return null;
}
}
@Override
protected final void onPostExecute(Result result) {
final WeakTarget target = mTarget.get();
if (target != null) {
this.onPostExecute(target, result);
}
}
protected void onPreExecute(WeakTarget target) {
// Nodefaultaction
}
protected abstract Result doInBackground(WeakTarget target,
Params... params);
protected void onPostExecute(WeakTarget target, Result result) {
// Nodefaultaction
}
}
使用也很簡單, 用法也幾乎和AsyncTask一樣:
private static class MyTask extends WeakAsyncTask<Void, Void, String, MainActivity> {
public MyTask(MainActivity target) {
super(target);
}
@Override
protected String doInBackground(MainActivity target, Void... params) { // 獲取context,
// 執行一些操作
Context context = target;
return "Hello Android !!!!!";
}
@Override
protected void onPostExecute(MainActivity target, String s) {
// 執行操作
}
}
直接呼叫執行:
new MyTask(this).execute();
其實還可以根據這個思想寫一個WeakHandler!
Android Weak Handler:可以避免記憶體洩漏的Handler庫
http://blog.csdn.net/jdsjlzx/article/details/51388862
本文部分來自:http://blog.csdn.net/zhuanglonghai/article/details/37909553
相關文章
- Android中使用Handler造成記憶體洩露的分析和解決Android記憶體洩露
- 如何定位和解決記憶體洩露記憶體洩露
- Android記憶體洩露分析以及工具的使用Android記憶體洩露
- 使用 mtrace 分析 “記憶體洩露”記憶體洩露
- Handler的使用、記憶體洩漏和解決記憶體
- Android中Handler引起的記憶體洩露Android記憶體洩露
- Android 中 Handler 引起的記憶體洩露Android記憶體洩露
- Lowmemorykiller記憶體洩露分析記憶體洩露
- IE中的記憶體洩露記憶體洩露
- Android記憶體優化——記憶體洩露檢測分析方法Android優化記憶體洩露
- JavaScript中的記憶體洩露模式JavaScript記憶體洩露模式
- Android中的Activitys, Threads和記憶體洩露Androidthread記憶體洩露
- Android 記憶體洩露詳解Android記憶體洩露
- Android 檢測記憶體洩露Android記憶體洩露
- 記憶體洩露記憶體洩露
- Java 中 ThreadLocal 記憶體洩露的例項分析Javathread記憶體洩露
- 記憶體洩露例項分析 -- Android記憶體優化第四彈記憶體洩露Android優化
- Android中使用Handler為何造成記憶體洩漏?Android記憶體
- 二、Android效能優化之記憶體洩露分析及工具使用Android優化記憶體洩露
- Android 記憶體洩漏案例和解析Android記憶體
- 避免使用不當pthread_create函式造成記憶體洩露thread函式記憶體洩露
- android Handler導致的記憶體洩露Android記憶體洩露
- 避免使用Handler而造成的記憶體洩漏記憶體
- js記憶體洩露JS記憶體洩露
- JavaScript記憶體洩露JavaScript記憶體洩露
- 記憶體洩露嗎記憶體洩露
- SHBrowseForFolder 記憶體洩露記憶體洩露
- JAVA記憶體洩露的原因及解決Java記憶體洩露
- 使用Windbg快速分析應用記憶體洩露問題記憶體洩露
- Linux記憶體洩露案例分析和記憶體管理分享Linux記憶體洩露
- 查詢並修復Android中的記憶體洩露—OutOfMemoryErrorAndroid記憶體洩露Error
- 解決git記憶體洩露問題Git記憶體洩露
- 如何診斷 Java 中的記憶體洩露Java記憶體洩露
- 記一次Go websocket 專案記憶體洩露排查 + 使用Go pprof定位記憶體洩露GoWeb記憶體洩露
- js記憶體洩露的原因JS記憶體洩露
- Java記憶體洩露的原因Java記憶體洩露
- JAVA 記憶體洩露的理解Java記憶體洩露
- Android 如何避免 Context 記憶體洩露AndroidContext記憶體洩露