Heim  >  Artikel  >  Was sind die Ursachen und Lösungen für Speicherlecks?

Was sind die Ursachen und Lösungen für Speicherlecks?

醉折花枝作酒筹
醉折花枝作酒筹Original
2021-05-17 16:10:3329618Durchsuche

Die Gründe und Lösungen sind: 1. Verwenden Sie statische interne Klassen, um durch Threads verursachte Speicherverluste zu vermeiden. 2. Verwenden Sie die zwischengespeicherte ConvertView, um durch ListView verursachte Speicherverluste zu vermeiden. 3. Löschen Sie den Inhalt der Sammlung, bevor Sie das Programm beenden , auf null setzen, um Speicherverluste im Sammelcontainer zu vermeiden.

Was sind die Ursachen und Lösungen für Speicherlecks?

Die Betriebsumgebung dieses Tutorials: Windows 7-System, Dell G3-Computer.

Häufige Ursachen für Speicherlecks

1. Speicherlecks durch Singletons

Aufgrund der statischen Natur des Singletons ist sein Lebenszyklus so lang wie der Lebenszyklus der Anwendung nicht mehr Es muss verwendet werden, aber das Singleton-Objekt enthält weiterhin einen Verweis auf das Objekt, wodurch verhindert wird, dass das Objekt normal recycelt wird, was zu einem Speicherverlust führt.

Beispiel: Verhindern Sie, dass Singleton-Instanzen Speicherverluste verursachen.

// 使用了单例模式
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. Speicherverluste, die durch die Erstellung statischer Instanzen nicht statischer innerer Klassen verursacht werden Dieselbe Datenressource kann wie folgt geschrieben werden:

  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. Speicherverlust durch Handler

Beispiel: Erstellen Sie ein statisches Objekt einer anonymen inneren Klasse

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. Aus der Android-Perspektive

Wenn die Android-Anwendung gestartet wird , erstellt der Hauptthread der Anwendung automatisch ein Looper-Objekt und die zugehörige MessageQueue. Wenn ein Handler-Objekt im Hauptthread instanziiert wird, wird es automatisch der MessageQueue des Hauptthread-Loopers zugeordnet. Alle an die MessageQueue gesendeten Nachrichten enthalten einen Verweis auf den Handler, sodass Looper die handleMessage()-Methode des Handles entsprechend zurückruft, um die Nachricht zu verarbeiten. Solange sich unverarbeitete Nachrichten in der MessageQueue befinden, holt der Looper diese weiterhin heraus und übergibt sie dem Handler zur Verarbeitung. Darüber hinaus begleitet das Looper-Objekt des Hauptthreads den gesamten Lebenszyklus der Anwendung.

2. Java-Perspektive

In Java enthalten nicht-statische innere Klassen und anonyme innere Klassen möglicherweise Verweise auf die äußeren Klassen, zu denen sie gehören, statische innere Klassen jedoch nicht.

Analysieren Sie das obige Beispiel: Wenn MainActivity endet, enthält die unverarbeitete Nachricht einen Verweis auf den Handler, und der Handler enthält einen Verweis auf die externe Klasse, zu der sie gehört, nämlich MainActivity. Diese Referenzbeziehung bleibt bestehen, bis die Nachricht verarbeitet wird. Dadurch wird verhindert, dass MainActivity vom Garbage Collector wiederverwendet wird, was zu einem Speicherverlust führt.

Lösung: Trennen Sie die Handler-Klasse oder verwenden Sie eine statische innere Klasse, um Speicherlecks zu vermeiden.

4. Durch Threads verursachte Speicherlecks

Beispiel: AsyncTask und 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 und Runnable verwenden beide anonyme innere Klassen, dann enthalten sie implizite Verweise auf die Aktivität, in der sie sich befinden. Wenn die Aufgabe nicht abgeschlossen ist, bevor die Aktivität zerstört wird, werden die Speicherressourcen der Aktivität nicht recycelt, was zu einem Speicherverlust führt.

Lösung: Trennen Sie die Klassen AsyncTask und Runnable oder verwenden Sie statische innere Klassen, um Speicherlecks zu vermeiden.

5. Durch nicht geschlossene Ressourcen verursachte Speicherlecks

Für Ressourcen wie BroadcastReceiver, ContentObserver, Datei, Cursor, Stream, Bitmap usw. sollten diese rechtzeitig geschlossen oder abgemeldet werden, wenn die Aktivität zerstört wird Ressourcen werden nicht recycelt, was zu einem Speicherverlust führt.

1) Beispielsweise ist ein BraodcastReceiver in der Aktivität registriert, die Registrierung des BraodcastReceiver wird jedoch nach Ende der Aktivität nicht aufgehoben.

2) Ressourcenobjekte wie Cursor, Stream, Datei usw. verwenden häufig einige Puffer. Wenn wir sie nicht verwenden, sollten wir sie rechtzeitig schließen, damit ihre Puffer rechtzeitig Speicher zurückgewinnen können. Ihre Puffer existieren nicht nur innerhalb der Java Virtual Machine, sondern auch außerhalb der Java Virtual Machine. Wenn wir die Referenzen einfach auf null setzen, ohne sie zu schließen, kommt es häufig zu Speicherverlusten.

3) Wenn ein Ressourcenobjekt nicht verwendet wird, sollte seine Funktion close() aufgerufen werden, um es zu schließen, und dann auf null gesetzt werden. Wir müssen sicherstellen, dass unsere Ressourcenobjekte geschlossen sind, wenn unser Programm beendet wird.

4) Rufen Sie recycle() auf, um Speicher freizugeben, wenn das Bitmap-Objekt nicht mehr verwendet wird. Bitmaps nach 2.3 sollten nicht mehr manuell recycelt werden müssen, da sich der Speicher bereits in der Java-Ebene befindet.

6. Speicherlecks bei Verwendung von ListView

ListView instanziiert zunächst eine bestimmte Anzahl von View-Objekten von BaseAdapter basierend auf dem aktuellen Bildschirmlayout und ListView speichert diese View-Objekte zwischen. Wenn die ListView nach oben gescrollt wird, wird das View-Objekt des ursprünglich oben befindlichen Elements wiederverwendet und dann zum Erstellen des darunter angezeigten Elements verwendet. Dieser Konstruktionsprozess wird durch die Methode getView() abgeschlossen. Der zweite formale Parameter ConvertView von getView() ist das View-Objekt des zwischengespeicherten Elements (wenn während der Initialisierung kein View-Objekt im Cache vorhanden ist, ist ConvertView null).

Beim Erstellen des Adapters wird die zwischengespeicherte ConvertView nicht verwendet.

Lösung: Verwenden Sie beim Erstellen des Adapters die zwischengespeicherte ConvertView.

7. Speicherleck im Sammelbehälter

Normalerweise fügen wir einige Objektreferenzen zu einem Sammlungscontainer hinzu (z. B. ArrayList). Wenn wir das Objekt nicht mehr benötigen, löschen wir seine Referenzen nicht aus der Sammlung, sodass die Sammlung immer größer wird. Wenn diese Sammlung statisch ist, ist die Situation noch ernster.

Lösung: Löschen Sie vor dem Beenden des Programms die Elemente in der Sammlung, setzen Sie sie dann auf Null und beenden Sie dann das Programm.

8. Durch WebView verursachter Verlust

Wenn wir das WebView-Objekt nicht verwenden, sollten wir seine Funktion destroy() aufrufen, um es zu zerstören und den Speicher freizugeben, den es für lange Zeit belegt hat kann nicht recycelt werden. Dies führt zu einem Speicherverlust.

Lösung: Öffnen Sie einen anderen Prozess für WebView und kommunizieren Sie über AIDL mit dem Hauptthread. Der Prozess, in dem sich WebView befindet, kann den geeigneten Zeitpunkt für die Zerstörung entsprechend den Geschäftsanforderungen auswählen und so eine vollständige Speicherfreigabe erreichen.

Für mehr Computerwissen besuchen Sie bitte die FAQ-Kolumne!

Das obige ist der detaillierte Inhalt vonWas sind die Ursachen und Lösungen für Speicherlecks?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Vorheriger Artikel:Was ist Koala live?Nächster Artikel:Was ist Koala live?