日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

内存泄漏的原因及解决办法是什么(常见引起引起内存泄漏的原因)

發(fā)布時間:2023/12/29 综合教程 39 生活家
生活随笔 收集整理的這篇文章主要介紹了 内存泄漏的原因及解决办法是什么(常见引起引起内存泄漏的原因) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

本教程操作環(huán)境:windows7系統(tǒng)、Dell G3電腦。

常見的內(nèi)存泄露造成的原因

1、單例造成的內(nèi)存泄漏

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

示例:防止單例導(dǎo)致內(nèi)存泄漏的實(shí)例

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

登錄后復(fù)制

2、非靜態(tài)內(nèi)部類創(chuàng)建靜態(tài)實(shí)例造成的內(nèi)存泄漏

例如,有時候我們可能會在啟動頻繁的Activity中,為了避免重復(fù)創(chuàng)建相同的數(shù)據(jù)資源,可能會出現(xiàn)如下寫法:

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

登錄后復(fù)制

3、Handler造成的內(nèi)存泄漏

示例:創(chuàng)建匿名內(nèi)部類的靜態(tài)對象

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);
            }
        });
    }
}

登錄后復(fù)制

1、從Android的角度

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

2、 Java角度

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

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

解決方法:將Handler類獨(dú)立出來或者使用靜態(tài)內(nèi)部類,這樣便可以避免內(nèi)存泄漏。

4、線程造成的內(nèi)存泄漏

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

登錄后復(fù)制

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

解決方法:將AsyncTask和Runnable類獨(dú)立出來或者使用靜態(tài)內(nèi)部類,這樣便可以避免內(nèi)存泄漏。

5、資源未關(guān)閉造成的內(nèi)存泄漏

對于使用了BraodcastReceiver,ContentObserver,F(xiàn)ile,Cursor,Stream,Bitmap等資源,應(yīng)該在Activity銷毀時及時關(guān)閉或者注銷,否則這些資源將不會被回收,從而造成內(nèi)存泄漏。

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

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

3)對于資源性對象在不使用的時候,應(yīng)該調(diào)用它的close()函數(shù)將其關(guān)閉掉,然后再設(shè)置為null。在我們的程序退出時一定要確保我們的資源性對象已經(jīng)關(guān)閉。

4)Bitmap對象不在使用時調(diào)用recycle()釋放內(nèi)存。2.3以后的bitmap應(yīng)該是不需要手動recycle了,內(nèi)存已經(jīng)在java層了。

6、使用ListView時造成的內(nèi)存泄漏

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

構(gòu)造Adapter時,沒有使用緩存的convertView。

解決方法:在構(gòu)造Adapter時,使用緩存的convertView。

7、集合容器中的內(nèi)存泄露

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

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

8、WebView造成的泄露

當(dāng)我們不要使用WebView對象時,應(yīng)該調(diào)用它的destory()函數(shù)來銷毀它,并釋放其占用的內(nèi)存,否則其長期占用的內(nèi)存也不能被回收,從而造成內(nèi)存泄露。

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

更多計(jì)算機(jī)相關(guān)知識,請?jiān)L問常見問題欄目!

以上就是內(nèi)存泄漏的原因及解決辦法是什么的詳細(xì)內(nèi)容,更多請關(guān)注風(fēng)君子博客其它相關(guān)文章!

總結(jié)

以上是生活随笔為你收集整理的内存泄漏的原因及解决办法是什么(常见引起引起内存泄漏的原因)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。