Android中的內(nèi)存泄漏:
概念:程序在申請內(nèi)存后商蕴,當(dāng)該內(nèi)存不需再使用但卻無法被釋放 & 歸還給程序的現(xiàn)象励烦,對應(yīng)用程序的影響贝或,容易使得應(yīng)用程序發(fā)生內(nèi)存溢出吼过,即?OOM锐秦,其實(shí)也就是當(dāng)一個對象使用完畢后,被另外一個對象持有并引用盗忱,導(dǎo)致無法被回收的現(xiàn)象叫內(nèi)存泄漏酱床。
內(nèi)存泄露的危害
內(nèi)存泄露的危害就是會使虛擬機(jī)占用內(nèi)存過高,導(dǎo)致OOM(內(nèi)存溢出)趟佃,程序出錯扇谣。
對于Android應(yīng)用來說,就是你的用戶打開一個Activity闲昭,使用完之后關(guān)閉它罐寨,內(nèi)存泄露;又打開汤纸,又關(guān)閉衩茸,又泄露;幾次之后贮泞,程序占用內(nèi)存超過系統(tǒng)限制,F(xiàn)C幔烛。
導(dǎo)致內(nèi)存泄漏的情況:可以說啃擦,書寫代碼的過程中任何情況都會出現(xiàn)內(nèi)存泄漏。但饿悬,總體來分析的話,有以下幾個原因:
一:線程導(dǎo)致的內(nèi)存泄漏:在Activity 銷毀之前令蛉,線程的任務(wù)并沒有執(zhí)行完畢,就會導(dǎo)致內(nèi)存泄漏狡恬。
解決辦法:將AsyncTask和Runnable類獨(dú)立出來或者使用靜態(tài)內(nèi)部類珠叔,這樣便可以避免內(nèi)存泄漏。
舉例:
public class MainActivity extends AppCompatActivity {
? ? @Override
? ? protected void onCreate(Bundle savedInstanceState) {
? ? ? ? super.onCreate(savedInstanceState);
? ? ? ? setContentView(R.layout.activity_main);
? ? ? ? new Thread(new MyRunnable()).start();
? ? ? ? new MyAsyncTask(this).execute();
? ? }
? ? class MyAsyncTask extends AsyncTask<Void, Void, Void> {
? ? ? ? // ...
? ? ? ? public MyAsyncTask(Context context) {
? ? ? ? ? ? // ...
? ? ? ? }
? ? ? ? @Override
? ? ? ? protected Void doInBackground(Void... params) {
? ? ? ? ? ? // ...
? ? ? ? ? ? return null;
? ? ? ? }
? ? ? ? @Override
? ? ? ? protected void onPostExecute(Void aVoid) {
? ? ? ? ? ? // ...
? ? ? ? }
? ? }
? ? class MyRunnable implements Runnable {
? ? ? ? @Override
? ? ? ? public void run() {
? ? ? ? ? ? // ...
? ? ? ? }
? ? }
}
二 :單例模式導(dǎo)致的內(nèi)存泄漏:因?yàn)閱卫撵o態(tài)屬性使得生命周期和應(yīng)用程序的生命周期一樣長弟劲。若1個對象已不需再使用而單例對象還持有該對象的引用祷安,那么該對象將不能被正常回收從而 導(dǎo)致內(nèi)存泄漏兔乞。
解決辦法:使用Appaction中context上下文汇鞭,因?yàn)檫@樣不管傳入什么Context最終將使用Application的Context,而單例的生命周期和應(yīng)用的一樣長庸追,這樣就防止了內(nèi)存泄漏霍骄。
// 使用了單例模式舉例:
public class AppManager {
? ? private static AppManager instance;
? ? private Context context;
? ? private AppManager(Context context) {
? ? ? ? this.context = context;
? ? }
? ? public static AppManager getInstance(Context context) {
? ? ? ? if (instance != null) {
? ? ? ? ? ? instance = new AppManager(context);
? ? ? ? }
? ? ? ? return instance;
? ? }
};
三:Handler造成的內(nèi)存泄漏:Handler是處理進(jìn)程間通信的機(jī)制淡溯,那么读整,當(dāng)MainActivity結(jié)束時,未處理的消息持有handler的引用咱娶,而handler又持有它所屬的外部類也就是MainActivity的引用米间。這條引用關(guān)系會一直保持直到消息得到處理煎楣,這樣阻止了MainActivity被垃圾回收器回收,從而造成了內(nèi)存泄漏车伞。
解決辦法:1:將Handler獨(dú)立出來择懂。2:將Handler聲明為靜態(tài)類 。3:在關(guān)閉Activity的時候停掉你的后臺線程另玖。線程停掉了困曙,就相當(dāng)于切斷了Handler和外部連接的線,Activity自然會在合適的時候被回收谦去。
舉例:注意這個時候Handler中增加了一個對Activity的弱引用(WeakReference)慷丽。
static class MyHandler extends Handler
? ? {
? ? ? ? WeakReference<Activity> mWeakReference;
? ? ? ? public MyHandler(Activity activity)
? ? ? ? {
? ? ? ? ? ? mWeakReference=new WeakReference<Activity>(activity);
? ? ? ? }
? ? ? ? @Override
? ? ? ? public void handleMessage(Message msg)
? ? ? ? {
? ? ? ? ? ? final Activity activity=mWeakReference.get();
? ? ? ? ? ? if(activity!=null)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? if (msg.what == 1)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? noteBookAdapter.notifyDataSetChanged();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? }