[JAVA] Achten Sie auf die Speicherbereinigung und vermeiden Sie Speicherlecks

Um Speicherlecks zu vermeiden, habe ich meines Wissens aufgelistet, wann die Speicherbereinigung funktioniert und wann nicht.

Über die Müllabfuhr

Eine Funktion, die ein Objekt nach Java-Ermessen automatisch zerstört, wenn es von keiner Variablen mehr verarbeitet wird. Die "finalize () -Methode" zerstört das Objekt, aber in Java kann das Timing nicht verwaltet werden, selbst wenn diese Methode definiert ist.

Fall, in dem die Speicherbereinigung funktioniert

Da ich es mit einem einfachen Vorgang bestätigt habe, habe ich den Heap-Bereich verkleinert, um Speicherlecks zu vermeiden. (Wie Speicherverlust bei 2M) Anfangsgröße von heap-Xms1m Maximale Heap-Größe - Xmx2m

① Wenn alle Variablen, die sich auf das Objekt beziehen, null werden

Da "einer Variablen Null zuweisen = die Variable kein Objekt darstellt", funktioniert dies, wenn alle Variablen, die ein bestimmtes Objekt darstellen, null werden. Substitute null = Es ist so, als würde man sagen "Ich benutze das nicht mehr", also wird Garbage Collection beurteilen, dass es unnötig ist.

public class AddList01 {
	public static void main(String[] args) {
		//Prozess 1
		List<String> list1 = new ArrayList<>();
		addList(list1);
		list1 = null;
		//Prozess 2
		List<String> list2 = new ArrayList<>();
		addList(list2);
		list2 = null;
	}

	private static void addList(List<String> list) {
		for (int i = 0; i < 100000; i++) {
			list.add("a");
		}
	}
}

② Wenn das Objekt nicht mehr bearbeitet wird

Die Speicherbereinigung funktioniert, wenn die Variable, die das Objekt verarbeitet, nicht mehr aufgeführt ist. "Ich habe die ganze Quelle gesehen, aber sie wird nicht mehr verarbeitet, daher ist es in Ordnung, den Inhalt wegzuwerfen."

public class AddList02 {
	public static void main(String[] args) {
		List<String> list1 = new ArrayList<>();
		List<String> list2 = new ArrayList<>();

		//Prozess 1
		for (int i = 0; i < 100000; i++) {
			list1.add("a");
		}

		//Prozess 2
		for (int i = 0; i < 100000; i++) {
			list2.add("b");
		}
	}
}

③ Lokale Variablen in Schleifen und Try-Catch

Die Speicherbereinigung funktioniert, wenn ein abgeschlossenes Objekt in einer Schleife, z. B. in einer Schleife deklariert oder instanziiert, die Schleife verlässt. Dies liegt daran, dass innerhalb der Schleife deklarierte Variablen nicht außerhalb der Schleife verarbeitet werden können.

public class AddList03 {
	public static void main(String[] args) {
		try {
			//Prozess 1
			for (int i = 0; i < 10; i++) {
				List<String> list1 = new ArrayList<>();
				for (int j = 0; j < 100000; j++) {
					list1.add("a");
				}
			}

			//Prozess 2
			List<String> list2 = new ArrayList<>();
			for (int i = 0; i < 10; i++) {
				list2 = new ArrayList<>();
				for (int j = 0; j < 100000; j++) {
					list2.add("b");
				}
			}

			//Prozess 3
			int i = 0;
			while (i < 10) {
				List<String> list3 = new ArrayList<>();
				for (int j = 0; j < 100000; j++) {
					list3.add("c");
				}
				i++;
			}

			//Prozess 4
			List<String> list4 = new ArrayList<>();
			for (int j = 0; j < 100000; j++) {
				list4.add("d");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		//Prozess 5
		List<String> list5 = new ArrayList<>();
		for (int j = 0; j < 100000; j++) {
			list5.add("e");
		}
	}
}

Übrigens, wenn die Variable "list2" nach der Schleife behandelt wird, bleibt nur die letzte Schleifeninstanz übrig.

public class AddList031 {
	public static void main(String[] args) {
		List<String> list2 = new ArrayList<>();
		for (int i = 0; i < 10; i++) {
			list2 = new ArrayList<>();
			for (int j = 0; j < 50000; j++) {
				list2.add("b");
			}
		}
		System.out.println(String.join("", list2));
	}
}

④ Lokale Variable der Methode

Es ist das gleiche Prinzip wie die Schleife von ③. Der Wert, auf den sich das Argument bezieht, und der Rückgabewert bleiben jedoch erhalten.

public class AddList04 {
	public static void main(String[] args) {
		addList();
		addList();
		addList();
	}

	private static void addList() {
		List<String> list = new ArrayList<>();
		for (int j = 0; j < 100000; j++) {
			list.add("a");
		}
	}
}

Fall, in dem die Speicherbereinigung nicht funktioniert

(1) Halten Sie die Instanz in der Hauptmethode und verweisen Sie auf das Objekt in einer anderen Methode.

In Fall (2), der funktioniert, wurde das Objekt, das nicht mehr behandelt wird, verworfen. Wenn Sie jedoch mit einer anderen Methode auf das Objekt verweisen, funktioniert die Garbage Collection nicht. Warum ist das?

public class AddList05 {
	public static void main(String[] args) {
		//Prozess 1
		List<String> list1 = new ArrayList<>();
		addList(list1);

		//Prozess 2
		List<String> list2 = new ArrayList<>();
		addList(list2);
	}

	private static void addList(List<String> list) {
		for (int i = 0; i < 100000; i++) {
			list.add("a");
		}
	}
}

(2) Eine Instanz der Liste wird im Feld generiert

Da es an verschiedenen Stellen in der Klasse verwendet wird, wird es im Feld beschrieben, sodass es nicht viele Argumente gibt. Der Umfang der Liste scheint zu groß zu sein, um zu entscheiden, dass die Speicherbereinigung nicht erforderlich ist.

public class AddList06 {
	private List<String> list1 = new ArrayList<>();
	private List<String> list2 = new ArrayList<>();

	public static void main(String[] args) {
		AddList06 addList06 = new AddList06();

		//Prozess 1
		for (int i = 0; i < 100000; i++) {
			addList06.list1.add("a");
		}

		//Prozess 2
		for (int i = 0; i < 100000; i++) {
			addList06.list2.add("a");
		}
	}
}

③ Was wurde als Rückgabewert der Methode empfangen

Auch wenn die Hauptmethode keine Instanz erstellt, bleibt diejenige erhalten, die von der aufgerufenen Methode erstellt und als Rückgabewert empfangen wird.

public class AddList07 {
	public static void main(String[] args) {
		//Prozess 1
		List<String> list = addList();

		//Prozess 2
		list = addList();

		//Prozess 3
		list = addList();
	}

	private static List<String> addList() {
		List<String> list = new ArrayList<>();
		for (int i = 0; i < 50000; i++) {
			list.add("a");
		}
		return list;
	}
}

④ Anstatt null zu ersetzen, versuche ich, es nicht anders zu verwenden.

Selbst wenn Sie die Listenmethode verwenden, um Werte zu löschen, die in der von Ihnen verwendeten Liste nicht mehr verwendet werden, scheint das Objekt weiterhin referenziert zu werden, da es nicht null ist.

public class AddList08 {
	public static void main(String[] args) {
		//Prozess 1
		List<String> list1 = new ArrayList<>();
		addList(list1);
		list1.clear();

		//Prozess 2
		List<String> list2 = new ArrayList<>();
		addList(list2);
		for (int i = 0; i < list2.size(); i++) {
			list2.remove(i);
		}

		//Prozess 3
		List<String> list3 = new ArrayList<>();
		addList(list3);
	}

	private static void addList(List<String> list) {
		for (int i = 0; i < 50000; i++) {
			list.add("a");
		}
	}
}

Zusammenfassung

Du denkst vielleicht, es ist nicht so einfach, aber vorerst ・ "Teilen Sie die Verarbeitung so weit wie möglich nach Methoden in kleine Teile und lassen Sie sie lokal ausführen." ・ "Verwenden Sie diese Option, wenn Sie sie wiederverwenden können, ohne vergeblich Variablen und Instanzen zu erstellen." ・ "Bitte deklarieren Sie keine Variablen im Feld" Ich fühlte, dass.

Wenn danach eine Verarbeitung wie SQL-Erfassung und Registrierung von DB erfolgt, wird diese nach Verarbeitungszweck aufgeteilt? Es kann einige Zeit dauern, wenn mehrere SQLs vorhanden sind, aber ich dachte, es wäre besser als die Verlangsamung der Verarbeitung.

Recommended Posts

Achten Sie auf die Speicherbereinigung und vermeiden Sie Speicherlecks
Um auf einfach zu lesenden Code zu achten
Beachten Sie den internen Zustand (Unveränderlichkeit) von Objekten und die Nebenwirkungen von Methoden
[Java] Inhalt der Collection-Schnittstelle und der List-Schnittstelle
5 Dinge, die neue Programmierer beachten sollten
Dinge, die Sie beim Schreiben von Java beachten sollten
[Java] Kurzschlüsse beachten (Kurzschlussauswertung)
Unterschied zwischen Mitglied und Sammlung von Schienen route.rb
Java Servlet sollte die Multithread-Umgebung kennen