가비지 컬렉션 언어에서는 (의도치 않게 객체를 살려두는) 메모리 누수를 찾기가 아주 까다롭다.
객체 참조 하나를 살려두면 가비지 컬렉터는 그 객체뿐 아니라 그 객체가 참조하는 모든 객체(그리고 또 그 객체들이 참조하는 모든 객체)를 회수해가지 못한다. 그래서 잠재적으로 성능에 악영향을 줄 수 있다.
해법
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());
}
}
'이펙티브 자바 > 2장 객체 생성과 파괴' 카테고리의 다른 글
아이템 9 try-finally 보다는 try-with-resources를 사용하라 (0) | 2023.12.19 |
---|---|
아이템 8 finalizer와 cleaner 사용을 피하라 (0) | 2023.12.19 |
아이템 6 불필요한 객체 생성을 피하라 (0) | 2023.12.18 |
아이템 5 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 (0) | 2023.12.18 |
아이템 4 인스턴스화를 막으려거든 private 생성자를 사용하라 (0) | 2023.12.18 |