Heim >Java >javaLernprogramm >Fallanalyse von Java-Speicherverlustproblemen

Fallanalyse von Java-Speicherverlustproblemen

WBOY
WBOYnach vorne
2023-05-23 18:46:061081Durchsuche

Java-Speicherleckproblem

Der sogenannte Speicherverlust bedeutet, dass ein Objekt oder eine Variable, die nicht mehr vom Programm verwendet wird, im Speicher belegt ist.

In Java gibt es einen Garbage-Collection-Mechanismus, der sicherstellen kann, dass, wenn auf ein Objekt nicht mehr verwiesen wird, das heißt, wenn das Objekt verwaist wird, das Objekt durch den Müll automatisch aus dem Speicher gelöscht wird Kollektor.

Da Java über einen Garbage-Collection-Mechanismus verfügt, warum gibt es immer noch ein Speicherverlustproblem?

Es ist nur so, dass einige Objekte nicht vom Garbage Collector verarbeitet werden können, was dazu führt, dass diese Objekte ständig den JVM-Speicher belegen, was zu Speicherverlusten führt.

Da Java einen gerichteten Graphen für die Speicherbereinigungsverwaltung verwendet, kann das Problem von Referenzzyklen beseitigt werden. Beispielsweise gibt es zwei Objekte, die aufeinander verweisen, solange sie nicht erreichbar sind Dann kann der GC sie auch recyceln. Der folgende Code kann in diesem Fall beispielsweise das Speicherrecycling sehen.

import java. io.IOException;
public class GarbageTest {

    public static void main(String[] args) throws IOException {
        try {
            // TODO Auto-generated method stub
            gcTest();
        } catch (IOException e) {
            e.printStackTrace();
        }

        System.out.println("has exited gcTest!");
        System.in.read();
        System.in.read();
        System.out.println("out begin gc!");
        for (int i = 0; i < 100; i++) {
            System.gc();
            System.in.read();
            System.in.read();
        }
    }

    private static void gcTest() throws IOException {
        System.in.read();
        System.in.read();
        Person p1 = new Person();
        System.in.read();
        System.in.read();
        Person p2 = new Person();
        p1.setMate(p2);
        p2.setMate(p1);
        System.out.println("before exit gctest!");
        System.in.read();
        System.in.read();
        System.gc();
        System.out.println("exit gctest!");
    }

    private static class Person {
        byte[] data = new byte[20000000];
        Person mate = null;

        public void setMate(Person other) {
            mate = other;
        }
    }

}

Speicherlecks in Java: Wenn langlebige Objekte Verweise auf kurzlebige Objekte enthalten, treten wahrscheinlich Speicherlecks auf, obwohl die kurzlebigen Objekte nicht mehr benötigt werden, da A langlebig ist Das Objekt enthält einen Verweis darauf und kann nicht recycelt werden. Laienhaft ausgedrückt kann es sein, dass der Programmierer ein Objekt erstellt und es dann nie wieder verwendet immer referenziert, das heißt, dieses Objekt ist nutzlos, kann aber nicht vom Garbage Collector recycelt werden. Dies ist ein möglicher Speicherverlust in Java.

Zum Beispiel laden wir im Cache-System ein Objekt und legen es in den Cache (z. B. in ein globales Kartenobjekt) und verwenden es dann nie wieder. Der Wert dieses Objekts ist Wird vom Cache referenziert, aber nicht mehr verwendet.

Um in Java nach Speicherlecks zu suchen, müssen Sie das Programm alle Zweige bis zum Ende des Programms vollständig ausführen lassen und dann prüfen, ob ein Objekt verwendet wurde. Wenn nicht, können Sie dies feststellen Das Objekt gehört zu einem Speicherverlust.

Wenn die Methode eines Instanzobjekts einer externen Klasse ein Instanzobjekt einer internen Klasse zurückgibt, wird das interne Klassenobjekt für lange Zeit referenziert, auch wenn das Instanzobjekt der externen Klasse nicht mehr verwendet wird , aber aufgrund der internen Klasseninstanzobjekte persistenter externer Klassen wird dieses externe Klassenobjekt nicht durch Müll gesammelt, was ebenfalls zu Speicherverlusten führt.

Der folgende Inhalt stammt aus dem Internet (die Hauptfunktion besteht darin, ein Element im Stapel zu löschen, nicht um es vollständig aus dem Array zu entfernen, sondern um die insgesamt gespeicherte Menge zu reduzieren. Ich kann es besser schreiben als dies Okay, wenn Sie ein Element entfernen, lassen Sie es aus dem Array verschwinden und setzen Sie den Wert der Position des Elements auf Null)

Ich kann mir wirklich nichts Klassischeres vorstellen als diesen Stapel Beispiele, Deshalb muss ich die Beispiele anderer Leute zitieren, die mir nicht eingefallen sind, sondern die, die ich in dem Buch gesehen habe. Natürlich könnte es mir nach einer Weile selbst einfallen, wenn ich sie nicht gesehen hätte , aber als ich dann sagte, dass ich selbst daran gedacht hätte, glaubte es niemand.

public class Stack {
    private Object[] elements = new Object[10];
    private int size = 0;

    public void push(Object e) {
        ensureCapacity();
        elements[size++] = e;
    }

    public Object pop() {
        if (size == 0) throw new EmptyStackException();
        return elements[--size];
    }

    private void ensureCapacity() {
        if (elements.length == size) {
            Object[] oldElements = elements;
            elements = new Object[2 * elements.length + 1];
            System.arraycopy(oldElements, 0, elements, 0, size);
        }
    }
}

Das obige Prinzip sollte sehr einfach sein. Wenn 10 Elemente zum Geldhaufen hinzugefügt werden und dann alle auftauchen, obwohl der Geldhaufen leer ist und wir nichts wollen, ist dies der Fall ist ein Objekt, das nicht recycelt werden kann. Es erfüllt die beiden Bedingungen für Speicherlecks. Es ist nutzlos und kann nicht recycelt werden. Aber selbst die Existenz eines solchen Dings hat möglicherweise keine Konsequenzen. Wenn dieser Haufen Geld weniger verwendet wird, werden nur ein paar K Speicher verschwendet. Wie auch immer, unser Gedächtnis ist bereits über G, also welche Auswirkungen wird es haben? ? Außerdem wird das Ding bald recycelt, also was macht das schon? Schauen wir uns unten zwei Beispiele an.

class Bad {
    public static Stack s = new Stack();
    static {
        s.push(new Object());

        s.pop(); //这里有一个对象发生内存泄露

        s.push(new Object());//上面的对象可以被回收了,等于是自愈了
    }
}

Da es statisch ist, bleibt es bestehen, bis das Programm beendet wird, aber wir können auch sehen, dass es über eine Selbstheilungsfunktion verfügt, was bedeutet, dass Ihr Stack maximal 100 Objekte enthält Es werden nur maximal 100 Objekte vorhanden sein, die nicht recycelt werden können. Tatsächlich sollte es leicht zu verstehen sein, dass der Stapel 100 Referenzen enthält verschwinden natürlich!

Eine weitere Situation eines Speicherverlusts: Wenn ein Objekt in der HashSet-Sammlung gespeichert wird, können die Felder im Objekt, die an der Berechnung des Hash-Werts beteiligt sind, nicht geändert werden. Andernfalls wird das geänderte Objekt geändert unterscheidet sich vom Hashwert, als er ursprünglich in der HashSet-Sammlung gespeichert wurde. In diesem Fall gibt die Methode „Not Found“ die aktuelle Referenz des Objekts als Parameter zum Abrufen des Objekts zurück Dies führt auch dazu, dass das aktuelle Objekt nicht einzeln aus der HashSet-Sammlung gelöscht werden kann, was zu einem Speicherverlust führt.

Anhang: Typische Situationen von Speicherlecks

(1) Temporäres Speicherleckproblem, das durch die Datenstruktur verursacht wird, siehe folgenden Code

public class Stack{  
      private Object[] element=new Object[10];  
      private int size=0;  
        
      public void push(Object ele){  
             ensureCapacity();  
             element[size++]=ele;  
      }  
  
      public Object pop(){  
             if(size==0) throw new EmptyStackException();  
             return element[--size]; //短暂造成内存泄露  
      }  
  
      private void ensureCapacity(){  
             if(element.length==size){  
                     Object[] oldElement=element;  
                     element=new Object[size*2+1];  
                     System.arraycopy(oldElement,0,element,0,size);  
             }  
      }  
}

Above Every Sobald der Code erscheint (), wird ein Element im Stapel angezeigt. Bevor ein neues Element hinzugefügt wird, gibt es tatsächlich noch ein Referenzelement[x], das auf das entfernte Objekt verweist, sodass der GC es nicht im Müll sammelt. Nur durch das Setzen von element[x]=newObject beim push() eines neuen Elements können zuvor erstellte Objekte recycelt werden. Es wäre viel sicherer, die obige pop()-Methode in den folgenden Code zu ändern:

public Object pop(){  
       if(element.length==size) throws EmptyStackException();  
       Object o=element[--size];  
       elements[size]=null;  //使得GC有机会回收这个对象  
       return o;  
}

Das obige ist der detaillierte Inhalt vonFallanalyse von Java-Speicherverlustproblemen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen