메모리 누수(Memory Leak)
C, C++과 같은 low level 언어와 달리 Java는 가비지 컬렉터가 참조되지 않는 객체를 알아서 회수(메모리에서 제거)하기 때문에 프로그래머가 명시적으로 객체를 방출할 필요가 없음
하지만, 실제로 앞으로 사용될 일이 없음에도 가비지 컬렉터가 회수하지 않는 객체들이 존재하게 될 수 있고, 이를
메모리 누수
라고 함이는 논리적으로 호출될 일이 없음에도 해당 객체들의 참조를 여전히 가지고 있기 때문에 발생하는 문제
이러한 사례를 예방하기 위해서는 다 쓴 참조를 null처리할 필요가 있음
하지만 매 객체를 미사용 순간마다 null로 처리하는 일은 코드를 필요 이상으로 지저분하게 만듦
그렇다면 어떨 때 명시적 null 처리를 수행해야 할까?
메모리 누수 사례와 해결 방법
자기 자신의 메모리를 직접 관리하는 클래스
Stack, Queue와 같은 Data Structure의 구현체가 이에 해당
이 경우 원소를 제거할 때(pop, deque 등) 명시적으로 해당 객체에 대한 자료구조 클래스의 참조를 null처리해 주는 것이 좋음
캐시
In-memory 캐시에 저장한 뒤, 해당 캐시가 사용되지 않음에도 해당 캐시에 대한 참조가 존재하면 이또한 메모리 누수에 해당
캐시 키에 대한 참조가 유지되는 동안 캐시가 유효하도록 구현할 수 있다면,
WeakHashMap
을 사용함으로써 이러한 누수를 예방할 수 있음WeakHashMap
이란, key에 대한 참조가 사라지면 해당 entry를 제거하는 Map 구현체
아니면 백그라운드에서 동작하는 스레드를 통해 캐시 사용 여부를 체크하거나, 직접 방출 알고리즘을 적용할 수도 있음
예시: LinkedHashMap으로 구현한 후 새 데이터가 추가될 때 지정된 MAX_SIZE를 넘었다면 removeEldestEntry를 통해 가장 오래된 데이터를 방출 (LRU)
리스너(Listener), 콜백(Callback)
리스너, 콜백은 클라이언트가 등록 후 명시적으로 해지해야 메모리에서 방출됨
즉, 별도 조치가 없으면 메모리에 계속 쌓이게 됨 (메모리 누수)
이를 예방하기 위해서는 이들을
약한 참조(weak reference)
로 저장해야 함이를 위해
WeakHashMap
을 사용할 수 있음
가장 좋은 메모리 관리 방법
명시적 null처리를 하기보다는, 변수를 최소한의 scope에 포함되도록 정의해 scope가 끝날 때 해당 scope 내에서 사용된 변수들이 가비지 컬렉터에 의해 자동으로 회수되도록 하는 것
Reference
https://blog.breakingthat.com/2018/08/26/java-collection-map-weakhashmap/
Last updated