개발 기록
[이펙티브 자바] 아이템 7,8 본문
(7) 다 쓴 객체 참조를 해제하라
가비지 컬렉터가 있더라도 메모리 관리에 신경써야 함! *메모리 누수*
가비지 컬렉션 언어에서는 메모리 누수를 찾기가 어려움.
객체 참조를 하나 살려두면 그 객체 + 그 객체가 참조하는 모든 객체 +.. 를 회수 하지 못 함.
해법!
1. 해당 참조를 다 썼을 때 null 처리 (참조 해제)
**예외적인 경우에 사용 : 자기 메모리를 직접 관리하는 클래스일때
ex. 스택 클래스에서 pop 메서드를 제대로 구현 (꺼낸 객체는 참조가 더 이상 필요 없음)
public Object pop() {
if (size = 0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null; // 다 쓴 참조 해제
return result;
}
2. WeakHashMap
: 더이상 사용하지 않는 객체를 GC할 때 자동으로 삭제해주는 Map
** 캐시 외부에서 키를 참조하는 동안만 엔트리가 살아 있는 캐시가 필요한 상황.
public static void main(String[] args) {
WeakHashMap<Integer, String> weakHashMap = new WeakHashMap<Integer, String>();
Integer key = new Integer(1);
weakHashMap.put(key, "1");
key = null;
// If GC is generated, the output changes to {}.
while (true) {
System.out.println(weakHashMap);
System.gc();
if (weakHashMap.size() == 0) {
break;
}
}
System.out.println("End");
}
해당 코를 실행해보면 key를 강하게 참조하는 곳이 없기 때문에 GC할 때 캐시가 지워진다.
참고로, String 클래스를 Key로 하는 WeakHashMap을 사용하면 의미가 없다. 왜냐하면 규칙 5에서 설명했듯이 String은 내부적으로 한 번 생성된 String에 대해 Constant Pool에 항상 참조가 존재하기 때문이다.
[출처] https://camel-context.tistory.com/42
리스너나 콜백도 약한 참조로 저장하면 가비지 컬렉터가 즉시 수거해감
- 콜백함수 : 다른 코드의 인수로서 넘겨주는 실행 가능한 코드
메모리 누수는 겉으로 잘 드러나지 않아 시스템에 수년간 잠복하는 사례도 있다.
이런 누수는 철저한 코드 리뷰나 힙 프로파일러 같은 디버깅 도구를 동원해야만 발견되기도 한다.
그래서 이런 종류의 문제는 예방법을 익혀두는 것이 매우 중요하다.
(8) finalizer와 cleaner 사용을 피하라
자바가 제공하는 두가지 객체 소멸자
1. finalizer
- 예측 할 수 없고, 상황에 따라 위험할 수 있어 일반적으로 불필요.
- 오동작, 낮은 성능, 이식성 문제의 원인
- finalizer 스레드는 다른 애플리케이션 스레드보다 우선순위가 낮아서 실행될 기회를 제대로 얻지 못할 수 있다.
- finalizer 동작 중 발생한 예외는 무시되며, 처리할 작업이 남았더라도 그 순간 종료된다.
- finalizer를 사용한 클래스는 finalizer 공격에 노출되어 심각한 보안 문제를 일으킬 수 있다.
2. cleaner
- 자바 9에서 finalizer 대안으로 소개
- 덜 위험하지만 여전히 예측할 수 없고, 느리고, 일반적으로 불필요
- 여전히 백그라운드에서 수행되며 가비지 컬렉터의 통제하에 있으니 즉각 수행되리라는 보장이 없다.
** 위 두가지 대신 쓸 수 있는 AutoCloseable 클래스
- 사용 방법 : AutoCloseable을 구현해주고, 클라이언트에서 인스턴스를 다 쓰고 나면 close 메서드를 호출
(일반적으로 예외가 발생해도 제대로 종료되도록 try-with-resources 를 사용)
public class AutoCloseableExample {
public static void main(String[] args) {
try (CustomResource customResource = new CustomResource()){
//close() 호출
} catch (Exception e){
e.printStackTrace();
}
}
}
public class CustomResource implements AutoCloseable {
@Override
public void close() throws Exception {
System.out.println("CustomResource Closed!");
}
}
'JAVA' 카테고리의 다른 글
[이펙티브자바] 아이템12 (0) | 2024.10.23 |
---|---|
[이펙티브 자바] 아이템 11 (1) | 2024.10.15 |
[이펙티브 자바] 아이템 6 (2) | 2024.10.03 |
[이펙티브 자바] 아이템 4,5 (3) | 2024.09.08 |
[이펙티브 자바] 아이템3 (0) | 2024.09.07 |