Java ist eine Art Müllsammlung. Sein Vorteil besteht darin, dass Entwickler nicht absichtlich die Speicherzuweisung verwalten müssen, was die Möglichkeit verringert, dass Anwendungen aufgrund lokaler Segmentierungsfehler abstürzen und verhindert, dass das Entflüssigkeitsspeicher den Stapel (HEAP) drückt. Daher ist der geschriebene Code sicherer.
Leider gibt es immer noch viele logische Lecks in Java, die anfällig für Speicherleckage sind. Wenn Sie nicht vorsichtig sind, kann Ihre Android-Anwendung leicht unfreien Speicher verschwenden, was letztendlich zu einem Fehlerwurf des Speicheres (außerhalb des Memorys, OOM) führt.
1. Der Grund für allgemeines Speicherleck ist, dass das Objekt nicht freigegeben wurde, wenn alle Verweise auf das Objekt freigegeben wurden. (Anmerkung des Übersetzers: Cursor vergessen zu schließen usw.)
2. Der Grund für logisches Speicherleck ist, dass, wenn die Anwendung dieses Objekt nicht mehr benötigt, alle Verweise auf das Objekt nicht freigegeben wurden.
Wenn Sie einen starken Hinweis auf ein Objekt haben, kann der Müllsammler das Objekt nicht im Speicher recyceln.
In der Android -Entwicklung ist das wahrscheinlichste Problem mit dem Speicherleck ein Kontext. Beispielsweise enthält der Kontext der Aktivität eine große Anzahl von Speicherreferenzen, wie z. B. Ansichtshierarchien und andere Ressourcen. Sobald ein Kontext durchgesickert ist, bedeutet dies auch, dass alle Objekte, auf die er verweist. Android -Maschinen haben einen begrenzten Speicher, und zu viele Speicherlecks können leicht zu OOM führen.
Das Erkennen von logischen Speicherlecks erfordert subjektives Urteilsvermögen, insbesondere der Lebenszyklus des Objekts ist nicht klar. Glücklicherweise hat die Aktivität einen klaren Lebenszyklus und es ist leicht, die Ursache des Lecks zu finden. Activity.onDestroy () wird als Ende des Aktivitätslebens angesehen. Programmatisch sollte es zerstört werden, oder das Android -System muss diesen Speicher recyceln (Anmerkung des Übersetzers: Wenn der Speicher nicht ausreicht, recyceln Android unsichtbare Aktivitäten).
Wenn diese Methode ausgeführt wird, gibt es immer noch einen starken Hinweis auf die Aktivität im Stapel, und der Müllsammler kann sie nicht als recyceltes Speicher markieren, und unser ursprünglicher Zweck ist es, sie zu recyceln!
Das Ergebnis ist, dass die Aktivität außerhalb ihres Lebenszyklus überlebt.
Aktivität ist ein Schwergewichtsobjekt und sollte vom Android -System behandelt werden. Logische Speicherlecks treten jedoch immer versehentlich auf. (Anmerkung des Übersetzers: Ich habe einmal eine Aktivität ausprobiert, die ein 20 -m -Speicherleck verursacht hat). In Android gibt es nur zwei Fallen, die zu potenziellen Speicherlecks führen:
Die statische Variable des globalen Prozesses (Prozess-Global). Dieses Monster, das den Zustand der Anwendung ignoriert und einen starken Hinweis auf die Aktivität hat.
Fäden, die außerhalb des Aktivitätslebenszyklus leben. Es wurden keine starken Hinweise auf Aktivität gelöscht.
Überprüfen Sie, ob Sie auf die folgenden Situationen gestoßen sind.
1.statische Aktivitäten
Die statische Aktivitätsvariable ist in der Klasse definiert, und die derzeit ausgeführte Aktivitätsinstanz wird dieser statischen Variablen zugeordnet.
Wenn diese statische Variable nach dem Ende des Aktivitätslebenszyklus nicht gelöscht wird, verursacht sie ein Speicherleck. Da statische Variablen den Lebenszyklus dieser Anwendung durchlaufen, existieren die durchgesickerten Aktivitäten im Bewerbungsprozess immer und werden vom Müllsammler nicht erfasst.
statische Aktivitätsaktivität; void setStaticActivity () {activity = this;} view sabutton = findViewById (r.id.sa_button);2. Statische Ansichten
Ähnliche Situationen können im Singleton -Modus auftreten, und wenn die Aktivität häufig verwendet wird, ist es praktisch, eine Instanz im Speicher zu speichern. Wie bereits erwähnt, ist es ziemlich gefährlich und unnötig, den Lebenszyklus einer Aktivität zu erzwingen, und es kann ohnehin nicht getan werden.
Sonderfall: Wenn eine Ansichtsinitialisierung viele Ressourcen verbraucht und während eines Aktivitätslebenszyklus unverändert bleibt, kann sie in statische und auf die Aussicht hierachy geladen werden. Wenn die Aktivität zerstört wird, sollte die Ressource veröffentlicht werden. (Anmerkung des Übersetzers: Der Speicher wird nicht im Beispielcode freigegeben. NULL diese statische Ansicht, aber es wird immer noch nicht empfohlen, die statische Ansichtsmethode zu verwenden.)
statische Ansicht; void setStaticView () {view = findViewById (r.id.sv_button);} view svbutton = findViewById (R.id.sv_button); }});3. Kursklassen
Weiter, unter der Annahme, dass es eine interne Klasse in der Aktivität gibt, kann dies die Lesbarkeit und Kapselung verbessern. Wenn wir eine interne Klasse erstellen und einen Verweis auf eine statische Variable haben, herzlichen Glückwunsch, ist das Speicherleck nicht weit von Ihnen entfernt (Anmerkung des Übersetzers: leer, wenn sie zerstört, ähm).
privates statisches Objekt innerlich; void createInnerClass () {Klasse Innerclass {} inner = new Innerclass ();} view icbutton = findViewById (r.id.ic_button);Einer der Vorteile interner Klassen ist, dass sie auf externe Klassen zugreifen können. Leider ist der Grund für Speicherlecks, dass die internen Klassen starke Hinweise auf externe Klasseninstanzen enthalten.
4. Anonyme Klassen
In ähnlicher Weise behalten anonyme Klassen auch Verweise auf externe Klassen bei. Speicherlecks sind also einfach zu erreichen, wenn Sie anonyme Asynctsk in Ihrer Aktivität definieren. Wenn die asynchrone Aufgabe eine zeitaufwändige Aufgabe im Hintergrund ausführt, wird die Aktivität leider zerstört (Anmerkung des Übersetzers: Benutzerausgänge, Systemrecycling), diese Aktivitätsinstanz, die von Asynctask gehalten wird, wird vom Müllsammler erst abgeschlossen.
void startaSynctask () {new Asynctask <void, void, void> () {@Override Protected void doInbackground (void ... params) {while (true); }} .execute ();} super.oncreate (savedInstancestate); setContentView (r.layout.Activity_main); view aicbutton = findViewById (r.id.at_button); aicbutton.setonclickListener (New View.onclick.onclIndieren) {@overraide public (New View. startaSyncTask ();5.Handler
Definieren Sie aus dem gleichen Grund anonyme Runnable und führen Sie es mit anonymer Klassenhandler aus. Die runnable innere Klasse wird einen impliziten Hinweis auf die externe Klasse haben und wird an die Messagequeue der Handler -Nachrichtenwarteschlange übergeben. Die Aktivitätsinstanz wird erst zerstört, wenn die Nachrichtennachricht verarbeitet wird, was zu einem Speicherleck führt.
void createHandler () {new Handler () {@Override public void Handlemessage (Nachrichtennachricht) {Super.handlemessage (Nachricht); }} .postDelayed (new Runnable () {@Override public void run () {while (true);}}, long.max_value >> 1);} view hbutton = findviewById (R.id.H_Button); v) {createHandler ();6. Threads
Wir zeigen noch einmal Speicherlecks durch Thread und Timertask.
void spawnthread () {new thread () {@Override public void run () {while (true); }} .Start ();} Ansicht tbutton = findViewById (r.id.t_button);7. Timertask
Solange es sich um eine Instanz einer anonymen Klasse handelt, unabhängig davon, ob es sich im Worker -Thread befindet oder nicht, wird ein Hinweis auf die Aktivität enthalten, was zu einem Speicherleck führt.
void enderuletimer () {new Timer (). Zeitplan (new timerTask () {@Override public void run () {while (trium);}}, long.max_value >> 1);} Ttbutton = findViewById (r.id.tt_button); @Override public void onclick (View v) {Scheduletimer ();8. Sensor Manager
Schließlich können die Systemdienste über Context.getSystemService (int -Name) erhalten werden. Diese Dienste arbeiten in ihren jeweiligen Prozessen und helfen Anwendungen, Hintergrundaufgaben und Hardware -Interaktionen zu erledigen. Wenn Sie diese Dienste nutzen müssen, können Sie Hörer registrieren, wodurch der Dienst einen Hinweis auf den Kontext hat. Wenn diese Zuhörer bei der Zerstörung der Aktivität nicht angemeldet sind, verursacht dies Speicherlecks.
void RegisterListener () {sensorManager sensorManager = (sensorManager) getSystemService (Sensor_Service); Sensor Sensor = sensorManager.getDefaultSensor (Sensor.Type_all); sensorManager.registerListener (this, sensor, sensorManager.Sensor_delay_fastest);} Ansicht smbutton = findViewById (r.id.sm_button); smbutton.setonclickListener (new View.onclickListener () {@overraide public void void (view) (venclick (vo. v) {{); }});Zusammenfassen
Nachdem so viele Beispiele gesehen werden, die zu Speicherlecks führen können, ist es einfach, den gesamten Speicher Ihres Telefons zu essen, die Müllsammlung und die Verarbeitung häufiger zu machen, und selbst im schlimmsten Fall wird dies zu OOM führen. Die Müllabfuhrbetriebe sind teuer und können zu sichtbaren Verzögerungen führen. Achten Sie daher beim Instanziieren der gehaltenen Referenzkette und führen Sie häufig Speicher -Leck -Überprüfungen durch.