Although Java has garbage collection capabilities, you sometimes have to manually reclaim expired object references.

Memory leaks are the first common source

For example, the following code has a memory leak.

// Can you spot the "memory leak"?
public class Stack {
    private Object[] elements;
    private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;
    public Stack() {
        elements = new Object[DEFAULT_INITIAL_CAPACITY];
    }
    public void push(Object e) {
        ensureCapacity();
        elements[size++] = e;
    }
    public Object pop() {
        if (size == 0)
            throw new EmptyStackException();
        return elements[--size];
    }
    /**
     * Ensure space for at least one more element, roughly
     * doubling the capacity each time the array needs to grow.
     */
    private void ensureCapacity() {
        if(elements.length == size) elements = Arrays.copyOf(elements, 2 * size + 1); }}Copy the code

So where is the memory leak? If a stack grows and then shrinks, the objects that were popped off the stack will not be garbage collected, even if the program using the stack has no more references to them. A stack push is followed by a pop, enlarged and then shrunk so that the pop-up object is not garbage collected. Do it right:

public Object pop() {
if (size == 0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null; // Eliminate obsolete reference
return result;
}
Copy the code

This is kind of turning my mind on its head. Because I rarely use an array and then assign null to an invalid element. For example, backtracking commonly used in DFS often Narrows an array:

stringBuilder.deleteCharAt(sb.length() - 1); // arraylist.remove (arraylist.size () -1);Copy the code

But I’ve never seen anyone unreference the last element that pops up. Nulling out object references should be the exception rather than the norm. Clearing references is the exception rather than the rule. All object references in the array are valid for GC, but we know that any references beyond size are useless so we need to reclaim them manually.

I saw an example on the Internet, how to write an example to get the compiler to prompt outOfMemory? To do this:

public class OutOfMemoryTest {
    public static void main(String[] args){
        List list=new ArrayList();
        for(;;) { int[] tmp=new int[1000000]; list.add(tmp); }}}Copy the code

By the way,

  1. Arrays.copyOfIntercepts or enlarges an array. New arrays that are enlarged are followed by null.
  2. The args of main’s String args[] is like an extra argument added to the command line.

Memory leaks are the second most common source

The cache. Object references placed in the cache are easily forgotten. WeakHashMap can be used.

Memory leaks are the third common source

Listeners and other callbacks. The solution is to use WeakReference. I remember writing register and Deregister interface a long time ago, but forget what it means.