android防止記憶體溢位淺析(二)

風的王子發表於2013-09-02


上次討論的 由於Bitmap引起的記憶體溢位相對比較容易發現,這次我們來看看相對比較難以發現的引起記憶體溢位的兩種情況。

一,Context引起的記憶體溢位:
在Android平臺上,長期保持一些資源的引用,造成一些記憶體不能釋放,帶來的記憶體洩露問題很多。比如Context。
android中的很多資原始檔都需要一個Context引用來載入,如果這些資源沒有被釋放,那麼Context的引用不為null,造成對應的Activity即使 呼叫了finish()但其佔有的記憶體依然不能被釋放。這是 因為在Java或者Android記憶體機制中,頂點的結點釋放前必須保證其他物件沒有呼叫才能被系統GC回收釋放。我們來看一段程式碼:

SoundManager.getInstance(this).play(SoundManger.MAIN_BG_SOUND);

從這段程式碼可以看出,聲音管理類是一個單例,它對於整個應用程式來說是全域性的,在進入應用的時候建立這個單例直到應用結束,這個單例才會被釋放。大家可以看到這個類在得到單例的時候需要傳遞一個Context物件作為引數,因為要利用Context來載入聲音資源。這就導致如果當前Activity呼叫了finish()全依然不能被GC,因為聲音管理類是全域性的,它持有了當前Activity的應用,阻止了其被GC。 解決的辦法是儘量使用全域性的Context來載入資源。修改如下:

SoundManager.getInstance(this.getApplicationContext).play(SoundManger.MAIN_BG_SOUND);

2 , Thread 執行緒引起的記憶體溢位:

先看程式碼:

private    class MyThread extends Thread
{
     @Override
     public void run()
     {
       super.run();
             while(bFlag)
             {
                //do somthing
             }
     }
}
MyThread mThread = new MyThread();
mThread.start();

這端程式碼 在主執行緒裡新開了一個執行緒,並且線上程裡迴圈處理一些邏輯。問題在於 如果控制執行緒結束的bFlag如果在Activity銷燬時沒有置為 false 將會產生很嚴重的後果。執行緒的一個特點是生命週期的不可控。如果Activity銷燬時,沒有結束執行緒的執行,那麼不僅阻止了Activity被GC,而且大大降低了程式的效能。假如,再重新進入這個Activity,那麼又建立了一個死迴圈的執行緒,而之前的那個執行緒依然在執行,這樣程式就會非常的卡。所以 一定要注意,銷燬Activity時一定要結束執行緒。

總而言之,想要避免context 相關的記憶體洩漏 ,記住以下幾點:
a.不要對activity 的context 長期引用( 一個activity 的引用的生存週期應該和activity 的生命週期相同)
b.試著使用關於application的 context 來替代和activity相關的context
c.如果一個acitivity 的非靜態內部類的生命週期不受控制,那麼避免使用它;使用一個靜態的內部類並且對其中的activity 使用一個弱引用。解決這個問題的方法是使用一個靜態的內部類,並且對它的外部類有一WeakReference,就像在ViewRoot中內部類W所做的就是這麼個例子。

相關文章