目錄
常見的記憶體外洩造成的原因
首頁 常見問題 記憶體洩漏的原因及解決方法是什麼

記憶體洩漏的原因及解決方法是什麼

May 17, 2021 pm 04:10 PM
內存洩漏

原因及解決方法為: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所在的進程可以根據業務的需要選擇合適的時機進行銷毀,從而達到記憶體的完整釋放。

更多電腦相關知識,請造訪常見問題欄位!

以上是記憶體洩漏的原因及解決方法是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1664
14
CakePHP 教程
1423
52
Laravel 教程
1319
25
PHP教程
1269
29
C# 教程
1248
24
Windows 上的暗黑破壞神 4 記憶體洩漏問題:如何修復 Windows 上的暗黑破壞神 4 記憶體洩漏問題:如何修復 Apr 13, 2023 pm 09:34 PM

Windows 上的暗黑破壞神 4 記憶體洩漏問題:13 種修復方法暗黑破壞神 4 的記憶體洩漏可能由多種問題引起。該遊戲目前仍處於開發階段,因此可以預料到此類問題。記憶體洩漏的主要原因似乎是暗黑破壞神 4 中的紋理品質設定。我們建議您從下面提到的第一個修復開始,然後瀏覽清單直到您設法解決問題。讓我們開始吧。方法 1:將紋理品質設定為中或低「高」紋理品質似乎是暗黑破壞神 4 記憶體洩漏的主要原因。這似乎是一個意想不到的錯誤,因為擁有高階 GPU 和工作站的用戶也報告說這是一個潛在的修復方法。前往您的暗黑

C#常見的記憶體管理問題及解決方法 C#常見的記憶體管理問題及解決方法 Oct 11, 2023 am 09:21 AM

C#中常見的記憶體管理問題及解決方法,需要具體程式碼範例在C#開發中,記憶體管理是一個重要的問題,不正確的記憶體管理可能會導致記憶體洩漏和效能問題。本文將向讀者介紹C#中常見的記憶體管理問題,並提供解決方法,並給出具體的程式碼範例。希望能幫助讀者更理解和掌握記憶體管理技術。垃圾回收器不及時釋放資源C#中的垃圾回收器(GarbageCollector)負責自動釋放不再使

golang記憶體洩漏原因有哪些 golang記憶體洩漏原因有哪些 Jan 10, 2023 pm 05:45 PM

洩漏原因有:1、time.After()的使用,每次time.After(duration x)會產生NewTimer(),在duration x到期前,新建立的timer不會被GC,到期才會GC;2、time.NewTicker資源未及時釋放;3、select阻塞;4、channel阻塞;5、申請過多的goroutine、goroutine阻塞;6、slice引起的等。

Go 記憶體洩漏追蹤:Go pprof 實作指南 Go 記憶體洩漏追蹤:Go pprof 實作指南 Apr 08, 2024 am 10:57 AM

pprof工具可用於分析Go應用程式的記憶體使用情況和偵測記憶體洩漏。它提供記憶體概況產生、記憶體洩漏識別和即時分析功能。透過使用pprof.Parse產生記憶體快照,並使用pprof-allocspace指令識別記憶體分配最多的資料結構。同時,pprof支援即時分析,並提供端點以遠端存取記憶體使用資訊。

解決閉包導致的記憶體洩漏問題 解決閉包導致的記憶體洩漏問題 Feb 18, 2024 pm 03:20 PM

標題:閉包造成的記憶體洩漏及解決方法引言:閉包是JavaScript中一個非常常見的概念,它可以讓內部函數存取外部函數的變數。然而,閉包在使用不當的情況下可能導致記憶體洩漏。本文將探討閉包所造成的記憶體洩漏問題,並提供解決方法及具體程式碼範例。一、閉包引起的記憶體洩漏問題閉包的特性是內部函數可以存取外部函數的變量,這意味著在閉包中引用的變數不會被垃圾回收。如果使用不當,

解決Go語言開發中的記憶體洩漏定位問題的方法 解決Go語言開發中的記憶體洩漏定位問題的方法 Jul 01, 2023 pm 12:33 PM

解決Go語言開發中的記憶體洩漏定位問題的方法記憶體洩漏是程式開發中常見的問題之一。在Go語言開發中,由於其自動垃圾回收機制的存在,記憶體洩漏問題相對其他語言可能較少。然而,當我們面對大型複雜的應用程式時,仍然可能會出現記憶體洩漏的情況。本文將介紹一些在Go語言開發中定位和解決記憶體洩漏問題的常用方法。首先,我們需要了解什麼是記憶體洩漏。簡單來說,記憶體洩漏指的是程式中

內存洩漏和內存溢出的區別是什麼 內存洩漏和內存溢出的區別是什麼 Dec 03, 2020 pm 05:22 PM

區別:記憶體溢出是指程式在申請記憶體時,沒有足夠的記憶體空間供其使用, 系統已經不能再分配出你所需要的空間;記憶體外洩是指程式在申請記憶體後,無法釋放已申請的記憶體空間,一次記憶體外洩危害可以忽略,但是記憶體洩漏次數多了就會導致記憶體溢位。

使用上下文裝飾器調試Pytorch的記憶體洩漏問題 使用上下文裝飾器調試Pytorch的記憶體洩漏問題 Apr 10, 2023 am 11:31 AM

裝飾器是 python 上下文管理器的特定實作。本片文章將透過一個pytorch GPU 偵錯的範例來說明如何使用它們。雖然它可能不適用於所有情況,但我它們卻非常有用。調試記憶體洩漏問題有很多方法可以調試記憶體洩漏。本文將展示一種識別程式碼中有問題的行的有用方法。此方法可以有助於以簡潔的方式找到具體的位置。逐行手動調試如果遇到問題,一種經典的且常用的方法是使用調試器逐行檢查,例如下面的例子:在搜尋引擎中查找有關如何計算pytorch 中所有張量總數的程式碼片段,例如:tensor -counter-s