站長資訊網
        最全最豐富的資訊網站

        內存泄漏的原因及解決辦法是什么

        原因及解決方法為:1、使用靜態內部類,避免線程造成的內存泄漏;2、使用緩存的convertView構造Adapter,避免使用ListView造成的內存泄漏;3、退出程序前,clear集合里的東西,置為null,避免集合容器中的內存泄露等。

        內存泄漏的原因及解決辦法是什么

        本教程操作環境:windows7系統、Dell G3電腦。

        常見的內存泄露造成的原因

        1、單例造成的內存泄漏

        由于單例的靜態特性使得其生命周期和應用的生命周期一樣長,如果一個對象已經不再需要使用了,而單例對象還持有該對象的引用,就會使得該對象不能被正常回收,從而導致了內存泄漏。

        示例:防止單例導致內存泄漏的實例

        // 使用了單例模式 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;     } }

        2、非靜態內部類創建靜態實例造成的內存泄漏

        例如,有時候我們可能會在啟動頻繁的Activity中,為了避免重復創建相同的數據資源,可能會出現如下寫法:

          public class MainActivity extends AppCompatActivity {      private static TestResource mResource = null;      @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_main);         if(mResource == null){             mResource = new TestResource();         }         //...     }          class TestResource {     //...     } }

        3、Handler造成的內存泄漏

        示例:創建匿名內部類的靜態對象

        public class MainActivity extends AppCompatActivity {      private final Handler handler = new Handler() {         @Override         public void handleMessage(Message msg) {             // ...         }     };      @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_main);          new Thread(new Runnable() {             @Override             public void run() {                 // ...                 handler.sendEmptyMessage(0x123);             }         });     } }

        1、從Android的角度

        當Android應用程序啟動時,該應用程序的主線程會自動創建一個Looper對象和與之關聯的MessageQueue。當主線程中實例化一個Handler對象后,它就會自動與主線程Looper的MessageQueue關聯起來。所有發送到MessageQueue的Messag都會持有Handler的引用,所以Looper會據此回調Handle的handleMessage()方法來處理消息。只要MessageQueue中有未處理的Message,Looper就會不斷的從中取出并交給Handler處理。另外,主線程的Looper對象會伴隨該應用程序的整個生命周期。

        2、 Java角度

        在Java中,非靜態內部類和匿名類內部類都會潛在持有它們所屬的外部類的引用,但是靜態內部類卻不會。

        對上述的示例進行分析,當MainActivity結束時,未處理的消息持有handler的引用,而handler又持有它所屬的外部類也就是MainActivity的引用。這條引用關系會一直保持直到消息得到處理,這樣阻止了MainActivity被垃圾回收器回收,從而造成了內存泄漏。

        解決方法:將Handler類獨立出來或者使用靜態內部類,這樣便可以避免內存泄漏。

        4、線程造成的內存泄漏

        示例:AsyncTask和Runnable

        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() {             // ...         }     } }

        AsyncTask和Runnable都使用了匿名內部類,那么它們將持有其所在Activity的隱式引用。如果任務在Activity銷毀之前還未完成,那么將導致Activity的內存資源無法被回收,從而造成內存泄漏。

        解決方法:將AsyncTask和Runnable類獨立出來或者使用靜態內部類,這樣便可以避免內存泄漏。

        5、資源未關閉造成的內存泄漏

        對于使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等資源,應該在Activity銷毀時及時關閉或者注銷,否則這些資源將不會被回收,從而造成內存泄漏。

        1)比如在Activity中register了一個BraodcastReceiver,但在Activity結束后沒有unregister該BraodcastReceiver。

        2)資源性對象比如Cursor,Stream、File文件等往往都用了一些緩沖,我們在不使用的時候,應該及時關閉它們,以便它們的緩沖及時回收內存。它們的緩沖不僅存在于 java虛擬機內,還存在于java虛擬機外。如果我們僅僅是把它的引用設置為null,而不關閉它們,往往會造成內存泄漏。

        3)對于資源性對象在不使用的時候,應該調用它的close()函數將其關閉掉,然后再設置為null。在我們的程序退出時一定要確保我們的資源性對象已經關閉。

        4)Bitmap對象不在使用時調用recycle()釋放內存。2.3以后的bitmap應該是不需要手動recycle了,內存已經在java層了。

        6、使用ListView時造成的內存泄漏

        初始時ListView會從BaseAdapter中根據當前的屏幕布局實例化一定數量的View對象,同時ListView會將這些View對象緩存起來。當向上滾動ListView時,原先位于最上面的Item的View對象會被回收,然后被用來構造新出現在下面的Item。這個構造過程就是由getView()方法完成的,getView()的第二個形參convertView就是被緩存起來的Item的View對象(初始化時緩存中沒有View對象則convertView是null)。

        構造Adapter時,沒有使用緩存的convertView。

        解決方法:在構造Adapter時,使用緩存的convertView。

        7、集合容器中的內存泄露

        我們通常把一些對象的引用加入到了集合容器(比如ArrayList)中,當我們不需要該對象時,并沒有把它的引用從集合中清理掉,這樣這個集合就會越來越大。如果這個集合是static的話,那情況就更嚴重了。

        解決方法:在退出程序之前,將集合里的東西clear,然后置為null,再退出程序。

        8、WebView造成的泄露

        當我們不要使用WebView對象時,應該調用它的destory()函數來銷毀它,并釋放其占用的內存,否則其長期占用的內存也不能被回收,從而造成內存泄露。

        解決方法:為WebView另外開啟一個進程,通過AIDL與主線程進行通信,WebView所在的進程可以根據業務的需要選擇合適的時機進行銷毀,從而達到內存的完整釋放。

        贊(0)
        分享到: 更多 (0)
        網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
        主站蜘蛛池模板: 欧美精品亚洲精品日韩专区va| 国产成人精品日本亚洲专一区| 精品无码一区二区三区爱欲九九| 国内精品久久久久久久久| 久久精品人人做人人爽电影蜜月 | 久久精品国产精品亚洲艾草网美妙 | 四虎精品免费永久免费视频| 2021国产精品视频网站| 久久99精品久久久久久动态图| 久久性精品| 国产精品女人呻吟在线观看| 久久99精品综合国产首页| 国产精品美女久久久久久2018| 亚洲精品无码日韩国产不卡?V| 国产精品成人免费观看 | 久久久久无码精品国产| 亚洲国产精品13p| 国产精品主播一区二区| 国产成人精品亚洲精品| 国产日韩精品在线| 99久久国产综合精品麻豆| 精品国产a∨无码一区二区三区| 亚洲国产另类久久久精品小说| 天天爽夜夜爽夜夜爽精品视频| 久久精品一区二区三区中文字幕| 国产精品 猎奇 另类视频| 国产69精品久久久久99尤物 | 久久久精品免费国产四虎| 500av导航大全精品| 成人区精品一区二区不卡| 久久亚洲精品中文字幕| 久久精品国产亚洲av麻豆小说| 日韩精品中文字幕无码一区| 久久亚洲精品成人AV| 国精无码欧精品亚洲一区| 国产成人亚洲精品青草天美 | 中文字幕日韩精品在线| 午夜精品久久久久久中宇| 欧美亚洲色综久久精品国产 | 99国产欧美精品久久久蜜芽| 国产精品视频网站你懂得|