[Effektives Java] Veraltete Objektreferenzen entfernen

Effektive Java-eigene Interpretation. Ich habe versucht, Punkt 7 der 3. Ausgabe zu interpretieren, indem ich meinen eigenen Code geschrieben habe.

Überblick

――In der Logik hat der Garbage Collector möglicherweise keine Möglichkeit, es zu erkennen, selbst wenn das Objekt nie wieder verwendet wird.

Vorausgesetztes Wissen

Müllabfuhr

Java verfügt über eine Funktion, mit der der Garbage Collector automatisch Objekte löscht, auf die nicht mehr verwiesen wird.

Im folgenden Code werden beispielsweise "hoge0", "hoge1", "hoge2" Objekte von "String" in der "for" -Schleife erstellt, aber die Referenzvariable "hoge" verschiebt das Referenzziel in der Reihenfolge. Die Objekte "hoge0", "hoge1" werden vom Garbage Collector gelöscht.

String hoge = null;

for (int i = 0; i < 3 ; i++){
    hoge = "hoge" + i;
}

del-object-Page-1.jpg

Andererseits wird das Objekt, dessen Referenz erhalten bleibt, nicht gelöscht und verbleibt auf unbestimmte Zeit im Speicher. Im folgenden Code werden die Objekte in einem Array gespeichert, jedoch mit "hoge [0]", "hoge [1]", "hoge [2]", "hoge0", "hoge1", "hoge2" "` Da jeder referenziert werden kann, wird er nicht in der Garbage Collection gelöscht und das Objekt bleibt im Speicher.

String[] hoges = new String[3];

for (int i = 0; i < 3; i++) {
    hoges[i] = "hoge" + i;
}

del-object-Copy of Page-1.jpg

Anti-Muster und Lösungen

Selbst gemachter Stapel

Ein Stapel ist eine Last In First Out-Datenstruktur. Es kann einfach über die Deque-Schnittstelle implementiert werden, aber hier wage ich es zu implementieren. Von Hand montieren.

** Hausgemachte Stapelklasse **

public class Stack {

    /**
     *Array für Stack
     */
    private String[] hoges;

    /**
     *Aktuelle Anzahl der Stapelelemente
     */
    private int currentElementCount = 0;

    /**
     *Konstrukteur
     *Definieren Sie die Größe des Stapels
     */
    public Stack() {
        this.hoges = new String[3];
    }

    /**
     *Zum Stapeln drücken
     *
     * @param str string zum pushen
     */
    public void push(String str) {
        hoges[currentElementCount] = str;
        currentElementCount = currentElementCount + 1;
    }

    /**
     *Pop vom Stapel
     *
     * @return Popped string
     */
    public String pop() {
        if (currentElementCount == 0) {
            throw new EmptyStackException();
        }
        currentElementCount = currentElementCount - 1;
        return hoges[currentElementCount];
    }
}

Wenn Sie diese Klasse machen, Push, können Sie sicher das Element bekommen, und wenn Sie Pop machen, können Sie das letzte Element bekommen, aber es gibt ein Problem. Da die Referenznummer nur beim Poppen verschoben wird, bleibt die Objektreferenz selbst erhalten.

del-object-Page-3 (1).jpg

Die Logik ist korrekt und das gepoppte Element wird nie wieder verwendet, aber der Garbage Collector kann nicht sagen, ob es gelöscht werden soll, da die Referenz erhalten bleibt. In diesem Beispiel beträgt die maximale Stapelgröße 3, sodass höchstens 3 Objekte im Speicher verbleiben. Große Stapel können jedoch zu schwerwiegenden Speichermangel führen. Dieses Problem kann gelöst werden, indem beim Hinzufügen und Löschen des Verweises auf das ursprüngliche Objekt absichtlich Null in das entsprechende Element des Arrays eingefügt wird.

del-object-Page-4.jpg

Wenn Sie den Stack jedoch wirklich verwenden möchten, verwenden Sie die Deque-Schnittstelle. Machen wir das.

Variablendeklaration wurde nicht verwendet

Manchmal ist es zu früh, eine Variable zu deklarieren, und das Objekt bleibt vergeblich im Speicher. Im folgenden Code gibt es ein Problem mit der Präfix-Deklaration.

/**
 *Gibt eine Folge von Zahlen bis zur angegebenen Anzahl von Schleifen zurück
 *Präfix hinzufügen, wenn die Länge den angegebenen Schwellenwert überschreitet
 *
 * @param limitLength String-Schwellenwert
 * @param loopCount Anzahl der Schleifen
 * @Eine von der Rücklaufschleife erstellte Zeichenfolge
 */
public String hoge(int limitLength, int loopCount) {

    String prefix = "Over" + limitLength + ": ";

    StringBuilder str = new StringBuilder();
    for (int i = 0; i < loopCount; i++) {
        str.append(i);
    }

    if (str.length() > limitLength) {
        return prefix + str;
    } else {
        return str.toString();
    }
}

Es gibt zwei Probleme.

Das obige Problem kann gelöst werden, indem es kurz vor dem Ort deklariert wird, an dem es wirklich verwendet wird, wie folgt.

    if (str.length() > limitLength) {
        String prefix = "Over" + limitLength + ": ";
        return prefix + str;
    } else {
        return str.toString();
    }

Bei einer langen Methode wird dies oft nicht unerwartet bemerkt. Seien Sie also vorsichtig.

Recommended Posts

[Effektives Java] Veraltete Objektreferenzen entfernen
[Read Effective Java] Kapitel 2 Punkt 6 "Veraltete Objektreferenzen entfernen"
Java (entfernen)
Effektives Java Kapitel 2
Effektives Java Kapitel 6 34-35
[Java] Objektklasse
Effektives Java Kapitel 4 15-22
Effektives Java Kapitel 3
Java Objektgrößengefühl
Effektive Java 3rd Edition Kapitel 2 Objekterstellung und Verschwindenlassen
Builder-Muster (effektives Java)
Java Object Serialization warum und wann
Muskel Java Objektorientierter Tag 1
Von ineffektivem Java zu effektivem Java