다쓴 객체의 참조 해제
import java.util.Arrays;
import java.util.EmptyStackException;
public class Stack<T> {
private T[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
elements = new T[DEFAULT_INITIAL_CAPACITY];
}
public void push(T e) {
ensureCapacity();
elements[size++] = e;
}
public T pop() {
if (size == 0) throw new EmptyStackException();
// return elements[--size]; //이러기만 하면 OOM 발생할 수도 있다.
T element = elements[--size];
element[size] = null; //이 코드가 필요하다.
return element;
}
private void ensureCapacity() {
if (elements.length == size) elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
위의 포인트와 같이 오래 사용하면 OutOfMemoryError를 피할 수 없는 경우들이 왕왕있다. 그래서 다 쓴 객체(Obsolete reference)를 참조 해제하는 것이
필요할 떄가 있다. 물론 Java는 C++ 같이 일일이 해제할 필요는 없다만
위의 경우와 같이 스택이 본인의 메모리를 직접 관리하는 경우 ( elements 배열로 풀을 만들어 관리 ) elements를 쓰는지 아닌지 GC는 알 길이 없다.
이와 같이 본인 메모리를 직접 관리하는 클래스라면 항상 MemoryLeak을 염두해야만 한다.
두 번째로 캐시 메모리도 누수 주범이다. 보통 그래서 TTL을 두거나 하는 식으로 관리한다. 혹은 WeakHashMap 등으로 방지할 수 있다.
- WeakHashMap
public class Fruit{
String name;
public Fruit(String name) {
this.name = name;
}
@Override
public String toString() {
return "Fruit{" +
"name='" + name + '\'' +
'}';
}
}
public class WeakHashMapExample {
public static void main(String[] args) {
WeakHashMap<Fruit, String> map = new WeakHashMap<>();
Fruit apple = new Fruit("apple");
Fruit orange = new Fruit("orange");
map.put(apple, "test a");
map.put(orange, "test b");
apple = null;
System.gc();
map.entrySet().forEach(System.out::println );
//Fruit{name='orange'}=test b
}
}
- WeakReference
class WeakReferenceExample {
static class TestObject {
String exam;
public TestObject(String exam) {
this.exam = exam;
}
@Override
public String toString() {
return "TestObject{" +
"exam='" + exam + '\'' +
'}';
}
}
public static void main(String[] args) {
TestObject strong = new TestObject("Strong");
TestObject weak = new TestObject("Weak");
TestObject bindStrong = strong;
WeakReference<TestObject> bindWeak = new WeakReference<TestObject>(weak);
System.out.println(bindStrong); //Strong
System.out.println(bindWeak.get());//Weak
strong = null;
weak = null;
System.gc();
//bindStrong null을 넣어도 객체 해제 X
//bindWeak null을 넣으면 객체 해제
System.out.println(bindStrong); //Strong
System.out.println(bindWeak.get());//null
}
}
마지막으로 리스너, 콜백 등이 달려 있는 경우다. (EventSource 같은)