이펙티브 자바/2장 객체 생성과 파괴

아이템 7 다 쓴 객체 참조를 해제하라

말랑공룡 2023. 12. 18. 16:43

 

가비지 컬렉션 언어에서는 (의도치 않게 객체를 살려두는) 메모리 누수를 찾기가 아주 까다롭다.

객체 참조 하나를 살려두면 가비지 컬렉터는 그 객체뿐 아니라 그 객체가 참조하는 모든 객체(그리고 또 그 객체들이 참조하는 모든 객체)를 회수해가지 못한다. 그래서 잠재적으로 성능에 악영향을 줄 수 있다.

 

해법

null 처리(참조 해제)하면 된다.

하지만 모든 객체를 다 쓰자마자 일일이 null 처리하는 것은 프로그램을 필요 이상으로 지저분하게 만들 뿐이다.

객체 참조를 null 처리하는 일은 예외적인 경우여야 한다.

 

더 좋은 해법

참조를 담은 변수를 유효 범위(scope) 밖으로 밀어내는 것이다.

 

나머지 메모리 누수 주범

캐시, 리스너, 콜백 역시 메모리 누수를 일으키는 주범이다.

WeakHashMap의 를 사용해 약한 참조(weak reference)로 저장하면 GC가 수거해 갈 것이다.

 

결론

자기 메모리를 직접 관리하는 클래스라면 프로그래머는 항시 메모리 누수에 주의해야 한다. (ex: stack)

 

참고: HashMap과 WeakHashMap

HashMap(강한 참조)

import java.util.HashMap;
import java.util.Map;

public class HashMapExample {
    public static void main(String[] args) {
        Map<Object, String> hashMap = new HashMap<>();

        Object key = new Object();
        String value = "Some value";

        // HashMap에 키-값 쌍 추가
        hashMap.put(key, value);

        // key를 null로 설정
        key = null;

        // HashMap은 여전히 key에 대한 참조를 유지하고 있음
        // 이 경우 key가 null이더라도 HashMap은 해당 키에 대한 참조를 유지하므로,
        // 가비지 컬렉션의 대상이 되지 않음
        System.gc();

        // HashMap의 크기는 1일 것이다.
        System.out.println("HashMap size: " + hashMap.size());
    }
}

 

WeakHashMap(약한 참조)

import java.util.Map;
import java.util.WeakHashMap;

public class Example {
    public static void main(String[] args) {
        Map<Object, String> weakMap = new WeakHashMap<>();

        Object key = new Object();
        String value = "Some value";

        // 약한 참조를 사용하여 키-값 쌍을 WeakHashMap에 추가
        weakMap.put(key, value);

        // 강력한 참조가 제거되면 가비지 컬렉터에 의해 WeakHashMap에서도 제거됨
        key = null;

        // someObject에 대한 강력한 참조가 더 이상 없으므로, 해당 키-값 쌍은 가비지 컬렉션의 대상이 됨
        System.gc();

        // WeakHashMap의 크기는 이제 0일 것이다.
        System.out.println("WeakHashMap size: " + weakMap.size());
    }
}