복잡한뇌구조마냥

[JAVA] Effective Java - 다 쓴 객체 참조를 해제하라 (7) 본문

BE/JAVA

[JAVA] Effective Java - 다 쓴 객체 참조를 해제하라 (7)

지금해냥 2025. 8. 3. 18:37

✅ 요약

Java는 가비지 컬렉터(GC)가 메모리를 자동으로 관리해주지만, 프로그래머의 실수로 인해 메모리 누수(Memory Leak) 가 발생할 수 있습니다. 특히, 다 쓴 객체를 참조한 채로 계속 유지하면 GC가 회수하지 못해 성능 저하와 OutOfMemoryError로 이어질 수 있습니다. 이를 방지하기 위해 다 쓴 참조는 명시적으로 해제하거나, 유효 범위를 벗어나게 하여 참조를 제거해야 합니다.

 


🔍 1. 왜 메모리 누수가 발생할까?

Java는 명시적인 free() 호출이 없기 때문에, 객체가 더 이상 사용되지 않더라도 참조만 유지되면 GC가 회수하지 않습니다.
즉, 다음과 같은 경우는 모두 메모리 누수로 이어질 수 있습니다:

  • 컬렉션(List, Map 등)에 넣은 뒤 제거하지 않음
  • 콜백이나 리스너 등록 후 해제하지 않음
  • 캐시 사용 후 청소하지 않음

객체의 생존 여부는 “사용 여부”가 아니라 “참조 여부”로 결정된다.

 


🧼 2. 해결 방법 – 참조 해제

💡 명시적으로 null 처리

사용이 끝난 객체의 참조를 null로 설정하면, 더 이상 참조하지 않음을 명확히 할 수 있습니다.

someResource = null;

단, 무조건 null 처리하는 습관은 오히려 코드 가독성을 해치고, NullPointerException을 유발할 수 있으므로 꼭 필요한 경우에만 사용하는 것이 좋습니다.

💡 가장 좋은 방법: 유효 범위 밖으로 밀어내기

가능하다면, 객체의 스코프(유효 범위)를 최소화하는 것이 가장 자연스러운 참조 해제 방법입니다.
예: 지역 변수는 메서드 종료 시 자동으로 GC 대상이 됨.

 


🧊 3. 캐시 사용 시 주의할 점

📌 캐시도 메모리 누수의 주범

캐시에 데이터를 저장한 뒤 제거하지 않으면 불필요한 객체들이 계속 남게 됩니다.

✅ 해결책 1: WeakHashMap 사용

WeakHashMap은 키에 대한 참조가 약(weak)하기 때문에, GC가 회수할 수 있으며, 더 이상 사용하지 않는 엔트리는 자동으로 제거됩니다.

Map<Key, Value> cache = new WeakHashMap<>();

✅ 해결책 2: LinkedHashMap의 removeEldestEntry() 오버라이드

캐시의 크기를 제한하거나, 오래된 데이터를 제거하는 방법입니다.

LinkedHashMap<String, Object> cache = new LinkedHashMap<>(16, 0.75f, true) {
    protected boolean removeEldestEntry(Map.Entry<String, Object> eldest) {
        return size() > MAX_CACHE_SIZE;
    }
};

✅ 해결책 3: 더 복잡한 캐시는 java.lang.ref 패키지 활용

SoftReference, WeakReference, PhantomReference 등을 사용해 메모리 상황에 따라 유연하게 캐시를 제어할 수 있습니다.


🔄 4. 리스너/콜백 관리도 중요

콜백이나 이벤트 리스너를 등록한 뒤 해제하지 않으면 계속 쌓이기만 하며 메모리 누수가 발생합니다.
이런 경우에도 약한 참조(WeakReference)를 사용하면 GC가 수거할 수 있습니다.

 


🧠 5. 디버깅과 예방이 핵심

  • 메모리 누수는 즉시 드러나지 않기 때문에, 수년간 발견되지 않다가 갑자기 OutOfMemoryError를 일으킬 수 있습니다.
  • 힙 프로파일러(VisualVM, Eclipse Memory Analyzer 등)를 사용해 누수를 확인할 수 있습니다.
  • 리뷰와 정적 분석 도구, 테스트를 통해 평소에 예방하는 습관이 중요합니다.

✍️ 마무리

Java는 메모리를 자동으로 관리하지만, 개발자가 직접 메모리 관리를 신경 써야 하는 경우도 있습니다.
특히, 다 쓴 객체의 참조를 해제하지 않으면 성능 저하와 치명적인 에러로 이어질 수 있기 때문에, 이를 방지하는 습관을 길러두는 것이 중요합니다.

“명확한 생명주기 관리 = 안정적인 프로그램 운영”

 

LIST