Eliminate obsolete object references-Chapter 2 Create and Destroy Objects-Effective Java Study Notes 06

The content of the article comes from the book Joshua Bloch-Effective Java (3rd)-2018.chm

Chapter two

Create and unregister objects

Item 7 Eliminate obsolete object references

If you switch from a manual memory management language (such as C or C++) to a garbage-collected language, such as java, your programmer’s job will become easier, because your objects will Automatic recycling.

It is easy to leave the impression that you don’t have to think about memory management, but this is not correct

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

There are no obvious errors in the program, and detailed tests will pass. But there is a hidden problem. It
may be that the program has memory overflow; in extreme cases, memory leak can cause disk paging and even program OutOfMemoryError, but it is relatively rare.

So where is the memory leak? If the stack grows first and then shrinks, the objects popped off the stack will not be garbage collected, even if the program using the stack no longer references them. This is due to obsolete references.
In this case, any reference outside the "active part" of the element array is obsolete. The active part consists of elements whose index is less than size

The solution to this type of problem is simple: clear the reference once it is obsolete. In the above example, as long as the object is popped off from the stack, it becomes obsolete.
Correct pop method:

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

Another benefit of eliminating obsolete references is that if they are subsequently dereferenced by mistake, the program will immediately fail with a NullPointerException instead of quietly doing the wrong thing. It is always beneficial to detect programming errors as quickly as possible.

When programmers fall into this pit for the first time, they may empty them all to overcompensate. This is neither necessary nor desirable.
Eliminating object references should be the exception, not the rule.
The best way to eliminate obsolete references is to get the variable containing the reference out of scope. This will happen naturally if you define each variable in the narrowest possible scope.

Generally speaking, whenever a class manages its own memory, programmers should be wary of memory leaks. Whenever an element is released, all object references contained in the element should be empty.

Another common source of memory leaks is cache.

If you happen to implement a cache, as long as there is a reference to its key outside the cache, the entry is related to it. Please express the cache as a WeakHashMap; the entry will be automatically deleted when it becomes obsolete.
Remember that WeakHashMap is easy to use, only when the required lifetime of the cache item is determined by the external reference to the key rather than the value

A more common situation is that the effective lifetime of a cache item is not clearly defined. As time goes by, the value of the cache item decreases. In these cases, the disabled entries in the cache should be cleared occasionally. This can be done by a background thread (perhaps ScheduledThreadPoolExecutor) or as a side effect of adding new items to the cache. The LinkedHashMap class simplifies the latter method through its removeEldestEntry method. For more complex caching, you may need to use java.lang.ref directly.

The third common source of memory leaks is listeners and other callbacks. If you implement an API where the client registers callbacks, but does not explicitly unregister them, unless you take some action, they will accumulate. One way to ensure that callbacks are garbage collected in time is to store only weak references to them, for example, only store them as keys in WeakHashMap.

Guess you like

Origin blog.csdn.net/weixin_43596589/article/details/112787497