Home  >  Article  >  Java  >  Java memory leak problem case analysis

Java memory leak problem case analysis

WBOY
WBOYforward
2023-05-23 18:46:06964browse

Java memory leak problem

The so-called memory leak means that an object or variable that is no longer used by the program has been occupied in the memory.

There is a garbage collection mechanism in Java, which can ensure that when an object is no longer referenced, that is, when the object becomes an orphan, the object will be automatically cleared from the memory by the garbage collector.

Since Java has a garbage collection mechanism, why is there still a memory leak problem?

Nothing more than that some objects cannot be processed by the garbage collector, causing these objects to occupy JVM memory all the time, which will lead to memory leaks.

Since Java uses a directed graph for garbage collection management, it can eliminate the problem of reference cycles. For example, if there are two objects that reference each other, as long as they are inaccessible to the root process, then the GC will also They can be recycled. For example, the following code can see the memory recycling in this case.

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;
        }
    }

}

Memory leaks in Java: If a long-lived object holds a reference to a short-lived object, a memory leak is likely to occur. Although the short-lived object is no longer needed, because of the long-lived The cyclic object holds its reference and cannot be recycled. This is the scenario where memory leaks occur in Java. In layman's terms, the programmer may create an object and then never use it again, but the object is always being used. Reference means that this object is useless but cannot be recycled by the garbage collector. This is the situation where memory leaks may occur in Java.

For example, in the cache system, we load an object and put it in the cache (for example, in a global map object), and then never use it again. The value of this object is referenced by the cache, but it is no longer used. Be used conveniently.

To check for memory leaks in Java, you must let the program execute all branches until the end of the program, and then see if an object has been used. If not, then you can determine that the object is a memory leak. .

If the method of an instance object of an outer class returns an instance object of an inner class, the inner class object is referenced for a long time, even if the outer class instance object is no longer used, but because the inner class persists outside Instance object of the class, this external class object will not be garbage collected, which will also cause memory leaks.

The following content comes from the Internet (the main feature is to clear an element in the stack, not to completely remove it from the array, but to reduce the total amount stored. I can write better than this, When removing an element, also make it disappear from the array, just set the value of the position of that element to null)

I really can't think of a more classic example than that stack, so Because I have to quote other people's examples, the following examples are not what I thought of, but what I saw in the book. Of course, if I didn't see it in the book, I might have thought of it myself after a while, but at that time I said I thought of it myself and no one believed it.

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);
        }
    }
}

The above principle should be very simple. If 10 elements are added to the pile of money, and then they all pop up, although the pile of money is empty and there is nothing we want, this is an object that cannot be recycled. This meets the two conditions of memory leaks. It is useless and cannot be recycled. But even if such a thing exists, it may not necessarily lead to any consequences. If this pile of money is used less, it will only waste a few K of memory. Anyway, our memory is already over G, so what impact will it have? , Besides, this thing will be recycled soon, so what does it matter? Let’s look at two examples below.

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

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

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

Because it is static, it will exist until the program exits, but we can also see that it has a self-healing function. That is to say, if your Stack has a maximum of 100 objects, then there will only be a maximum of 100 objects. It cannot be recycled. In fact, this should be easy to understand. Stack holds 100 references internally. The worst case scenario is that they are all useless, because once we put new progress, the previous references will naturally disappear!

Another situation of memory leak: When an object is stored in the HashSet collection, the fields in the object that participate in calculating the hash value cannot be modified. Otherwise, the object will be modified. The value is different from the hash value when it was originally stored in the HashSet collection. In this case, even if the contains method uses the current reference of the object as a parameter to retrieve the object from the HashSet collection, it will return the object not found. As a result, this will also result in the inability to individually delete the current object from the HashSet collection, causing a memory leak.

Attachment: Typical situations of memory leaks

(1) The short-term memory leak problem caused by the data structure, see the following 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);  
             }  
      }  
}

The above code pops () every time Stack will pop up an element every time. Before adding a new element, there is actually still a reference element[x] pointing to the popped object, so the GC will not garbage collect it. Only by setting element[x]=newObject when pushing() a new element can previously created objects be recycled. It would be much safer to change the pop() method above to the following code:

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

The above is the detailed content of Java memory leak problem case analysis. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete