Heim Java javaLernprogramm So schreiben Sie einen Code in Java, um einen Speicherverlust zu verursachen

So schreiben Sie einen Code in Java, um einen Speicherverlust zu verursachen

Nov 25, 2016 am 10:42 AM
java java代码

Der Text stammt aus einer beliebten Diskussion auf der StackOverflow-Q&A-Website: Wie schreibe ich einen Code in Java, der Speicherlecks verursacht?

F: Ich habe gerade an einem Interview teilgenommen und der Interviewer hat mich gefragt, wie man Java-Code schreibt, der Speicherverluste verursacht. Ich habe keine Ahnung von dieser Frage, die so peinlich ist.

A1: Durch die folgenden Schritte kann es leicht zu Speicherlecks kommen (Programmcode kann nicht auf bestimmte Objekte zugreifen, diese werden aber dennoch im Speicher gespeichert):

Die Anwendung erstellt einen Thread mit langer Laufzeit (bzw Verwenden Sie einen Thread-Pool, wodurch Speicher schneller verloren geht.

Der Thread lädt eine Klasse über einen Klassenlader (kann angepasst werden).

Diese Klasse weist einen großen Speicherblock zu (z. B. neues Byte [1000000]), speichert eine starke Referenz in einer statischen Variablen und speichert dann ihre eigene Referenz in ThreadLocal. Das Zuweisen von zusätzlichem Speicher (neues Byte[1000000]) ist optional (Klasseninstanzlecks sind ausreichend), aber dadurch wird der Speicherverlust schneller.

Der Thread bereinigt die benutzerdefinierte Klasse oder den Klassenlader, der die Klasse lädt.

Wiederholen Sie die oben genannten Schritte.

Da es keine Verweise auf die Klasse und den Klassenlader gibt, kann nicht auf den Speicher in ThreadLocal zugegriffen werden. ThreadLocal enthält einen Verweis auf das Objekt sowie einen Verweis auf die Klasse und ihren Klassenlader. Der Klassenlader enthält alle Verweise auf die von ihm geladenen Klassen, sodass der GC den in ThreadLocal gespeicherten Speicher nicht zurückfordern kann. In vielen JVM-Implementierungen werden Java-Klassen und Klassenlader direkt dem Permgen-Bereich zugewiesen, ohne dass eine GC durchgeführt wird, was zu schwerwiegenderen Speicherlecks führt.

Eine Variante dieses Leckmusters besteht darin, dass es leicht zu Speicherlecks kommt, wenn Sie Anwendungen und Anwendungscontainer (z. B. Tomcat), die ThreadLocal in irgendeiner Form verwenden, häufig erneut bereitstellen (da der Anwendungscontainer ThreadLocal wie zuvor verwendet). (Bei jedem erneuten Bereitstellen der Anwendung wird ein neuer Klassenlader verwendet.)

A2:

Statisches Variablenreferenzobjekt

class MemorableClass {
    static final ArrayList list = new ArrayList(100);
}
Nach dem Login kopieren

String.intern() einer langen Zeichenfolge aufrufen

String str=readString(); // read lengthy string any source db,textbox/jsp etc..
// This will place the string in memory pool from which you cant remove
str.intern();
Nach dem Login kopieren

Nicht geschlossener geöffneter Stream (Datei, Netzwerk usw.)

try {
    BufferedReader br = new BufferedReader(new FileReader(inputFile));
    ...
    ...
} catch (Exception e) {
    e.printStacktrace();
}
Nach dem Login kopieren

Ungeschlossene Verbindung

try {
    Connection conn = ConnectionFactory.getConnection();
    ...
    ...
} catch (Exception e) {
    e.printStacktrace();
}
Nach dem Login kopieren

GC nicht erreichbarer Bereich der JVM

Zum Beispiel durch native Methoden zugewiesener Speicher.

Webanwendungsobjekte im Anwendungsbereich, die Anwendung wurde nicht neu gestartet oder nicht explizit entfernt

getServletContext().setAttribute("SOME_MAP", map);

web Anwendungsobjekte im Sitzungsbereich, die nicht ungültig gemacht oder nicht explizit entfernt wurden

session.setAttribute("SOME_MAP", map);

Falsche oder unangemessene JVM-Optionen

Zum Beispiel , IBM JDKs noclassgc verhindert die Garbage Collection nutzloser Klassen

A3: Wenn HashSet hashCode() oder equal() nicht korrekt implementiert (oder nicht implementiert), führt dies dazu, dass weiterhin „Kopien“ hinzugefügt werden die Sammlung. Wenn die Sammlung die Elemente, die sie ignorieren sollte, nicht ignoriert, kann ihre Größe nur weiter wachsen und die Elemente können nicht gelöscht werden.

Wenn Sie falsche Schlüssel-Wert-Paare generieren möchten, können Sie wie folgt vorgehen:

class BadKey {
   // no hashCode or equals();
   public final String key;
   public BadKey(String key) { this.key = key; }
}
  
Map map = System.getProperties();
map.put(new BadKey("key"), "value"); // Memory leak even if your threads die.
Nach dem Login kopieren

A4: Zusätzlich zu vergessenen Listenern und statischen Referenzen ist der Schlüssel in der Hashmap falsch /is Typische Speicherverlustszenarien wie Änderungen oder Thread-Blockierungen, die den Lebenszyklus nicht beenden können. Hier sind einige weniger offensichtliche Speicherverlustsituationen in Java, die hauptsächlich mit Threads zusammenhängen.

Runtime.addShutdownHook wird nach runtime.addShutdownHook nicht entfernt. Aufgrund des Fehlers der ThreadGroup-Klasse für nicht gestartete Threads wird es möglicherweise nicht recycelt, was zu einem Speicherverlust in der ThreadGroup führt.

Den Thread erstellen, aber nicht starten, gleiche Situation wie oben

Erstellen Sie einen Thread, der ContextClassLoader und AccessControlContext erbt, verwenden Sie ThreadGroup und InheritedThreadLocal, alle diese Referenzen sind potenzielle Lecks und alle sind geladene Klassen durch den Klassenlader und alle statischen Referenzen und so weiter. Dies hat ganz offensichtliche Auswirkungen auf die ThreadFactory-Schnittstelle als wichtigen Bestandteil des gesamten j.u.c.Executor-Frameworks (java.util.concurrent), und viele Entwickler haben die potenziellen Gefahren nicht bemerkt. Und viele Bibliotheken starten Threads entsprechend den Anforderungen.

ThreadLocal-Caching ist in vielen Fällen keine gute Praxis. Es gibt viele Implementierungen von einfachem Caching, die auf ThreadLocal basieren, aber der ContextClassLoader wird auslaufen, wenn der Thread weiterhin außerhalb seines erwarteten Lebenszyklus ausgeführt wird. Verwenden Sie ThreadLocal-Caching nicht, es sei denn, dies ist wirklich erforderlich.

ThreadGroup.destroy() wird aufgerufen, wenn ThreadGroup selbst keine Threads, aber dennoch untergeordnete Thread-Gruppen hat. Wenn ein Speicherverlust auftritt, kann die Thread-Gruppe nicht aus ihrer übergeordneten Thread-Gruppe entfernt werden und untergeordnete Thread-Gruppen können nicht aufgelistet werden.

Bei Verwendung von WeakHashMap bezieht sich der Wert direkt (indirekt) auf den Schlüssel, was schwierig zu finden ist. Dies gilt auch, wenn eine Klasse, die Weak/SoftReference erbt, möglicherweise einen starken Verweis auf das geschützte Objekt enthält.

Verwenden Sie die java.net.URL des http(s)-Protokolls, um Ressourcen herunterzuladen. KeepAliveCache erstellt einen neuen Thread in der System-ThreadGroup, wodurch der Speicher des Kontextklassenladers des aktuellen Threads verloren geht. Der Thread wird bei der ersten Anfrage erstellt, wenn es keinen überlebenden Thread gibt, sodass ein Leck sehr wahrscheinlich ist. (Dies wurde in Java 7 behoben, sodass der Thread-Erstellungscode den Kontextklassenlader ordnungsgemäß entfernt.)

Verwenden Sie InflaterInputStream, um neue java.util.zip.Inflater() im Konstruktor (z. B. PNGImageDecoder) zu übergeben, ohne end() des Inflaters aufzurufen. Just new ist sehr sicher, aber wenn Sie die Klasse selbst als Konstruktorparameter erstellen und close() des Streams aufrufen und den Inflater nicht schließen können, kann es zu Speicherlecks kommen. Dabei handelt es sich nicht wirklich um einen Speicherverlust, da er vom Finalizer freigegeben wird. Dies verbraucht jedoch viel nativen Speicher, was dazu führt, dass oom_killer von Linux den Prozess abbricht. Die Lektion, die wir daraus lernen, lautet also: Geben Sie native Ressourcen so früh wie möglich frei.

Das Gleiche gilt für java.util.zip.Deflater, was noch schwerwiegender ist. Das Gute ist, dass Deflater selten verwendet wird. Wenn Sie selbst einen Deflater oder Inflater erstellen, denken Sie daran, dass Sie end() aufrufen müssen.


Erklärung dieser Website
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

Heiße KI -Werkzeuge

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Clothoff.io

Clothoff.io

KI-Kleiderentferner

AI Hentai Generator

AI Hentai Generator

Erstellen Sie kostenlos Ai Hentai.

Heiße Werkzeuge

Notepad++7.3.1

Notepad++7.3.1

Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6

Dreamweaver CS6

Visuelle Webentwicklungstools

SublimeText3 Mac-Version

SublimeText3 Mac-Version

Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Perfekte Zahl in Java Perfekte Zahl in Java Aug 30, 2024 pm 04:28 PM

Leitfaden zur perfekten Zahl in Java. Hier besprechen wir die Definition, Wie prüft man die perfekte Zahl in Java?, Beispiele mit Code-Implementierung.

Weka in Java Weka in Java Aug 30, 2024 pm 04:28 PM

Leitfaden für Weka in Java. Hier besprechen wir die Einführung, die Verwendung von Weka Java, die Art der Plattform und die Vorteile anhand von Beispielen.

Smith-Nummer in Java Smith-Nummer in Java Aug 30, 2024 pm 04:28 PM

Leitfaden zur Smith-Zahl in Java. Hier besprechen wir die Definition: Wie überprüft man die Smith-Nummer in Java? Beispiel mit Code-Implementierung.

Fragen zum Java Spring-Interview Fragen zum Java Spring-Interview Aug 30, 2024 pm 04:29 PM

In diesem Artikel haben wir die am häufigsten gestellten Fragen zu Java Spring-Interviews mit ihren detaillierten Antworten zusammengestellt. Damit Sie das Interview knacken können.

Brechen oder aus Java 8 Stream foreach zurückkehren? Brechen oder aus Java 8 Stream foreach zurückkehren? Feb 07, 2025 pm 12:09 PM

Java 8 führt die Stream -API ein und bietet eine leistungsstarke und ausdrucksstarke Möglichkeit, Datensammlungen zu verarbeiten. Eine häufige Frage bei der Verwendung von Stream lautet jedoch: Wie kann man von einem Foreach -Betrieb brechen oder zurückkehren? Herkömmliche Schleifen ermöglichen eine frühzeitige Unterbrechung oder Rückkehr, aber die Stream's foreach -Methode unterstützt diese Methode nicht direkt. In diesem Artikel werden die Gründe erläutert und alternative Methoden zur Implementierung vorzeitiger Beendigung in Strahlverarbeitungssystemen erforscht. Weitere Lektüre: Java Stream API -Verbesserungen Stream foreach verstehen Die Foreach -Methode ist ein Terminalbetrieb, der einen Vorgang für jedes Element im Stream ausführt. Seine Designabsicht ist

Zeitstempel für Datum in Java Zeitstempel für Datum in Java Aug 30, 2024 pm 04:28 PM

Anleitung zum TimeStamp to Date in Java. Hier diskutieren wir auch die Einführung und wie man Zeitstempel in Java in ein Datum konvertiert, zusammen mit Beispielen.

Java -Programm, um das Kapselvolumen zu finden Java -Programm, um das Kapselvolumen zu finden Feb 07, 2025 am 11:37 AM

Kapseln sind dreidimensionale geometrische Figuren, die aus einem Zylinder und einer Hemisphäre an beiden Enden bestehen. Das Volumen der Kapsel kann berechnet werden, indem das Volumen des Zylinders und das Volumen der Hemisphäre an beiden Enden hinzugefügt werden. In diesem Tutorial wird erörtert, wie das Volumen einer bestimmten Kapsel in Java mit verschiedenen Methoden berechnet wird. Kapselvolumenformel Die Formel für das Kapselvolumen lautet wie folgt: Kapselvolumen = zylindrisches Volumenvolumen Zwei Hemisphäre Volumen In, R: Der Radius der Hemisphäre. H: Die Höhe des Zylinders (ohne die Hemisphäre). Beispiel 1 eingeben Radius = 5 Einheiten Höhe = 10 Einheiten Ausgabe Volumen = 1570,8 Kubikeinheiten erklären Berechnen Sie das Volumen mithilfe der Formel: Volumen = π × R2 × H (4

Wie führe ich Ihre erste Spring -Boot -Anwendung in der Spring Tool Suite aus? Wie führe ich Ihre erste Spring -Boot -Anwendung in der Spring Tool Suite aus? Feb 07, 2025 pm 12:11 PM

Spring Boot vereinfacht die Schaffung robuster, skalierbarer und produktionsbereiteter Java-Anwendungen, wodurch die Java-Entwicklung revolutioniert wird. Der Ansatz "Übereinkommen über Konfiguration", der dem Feder -Ökosystem inhärent ist, minimiert das manuelle Setup, Allo

See all articles