티스토리 뷰
자바의 객체 소멸자
자바는 finalizer 와 cleaner 라는 두 가지 객체소멸자를 제공한다. finalizer는 예측할 수 없고, 상황에 따라 위험할 수 있어 일반적으로 불필요하다. cleaner는 finalizer 보다는 덜 위험하지만, 여전히 예측할 수 없고, 느리고, 일반적으로 불필요하다
자바의 객체 소멸자는 C++의 파괴자(destructor) 와는 다른 개념이다. C++의 파괴자가 자원회수를 명시적으로 표현하는 반면, finaizer와 cleaner는 즉시 수행된다는 보장이 없다. 이 소멸자로는 제때 실행되어야 하는 작업은 절대 할 수 없다. 상태를 영구적으로 수정하는 작업에서는 절대 자바의 객체 소멸자를 사용해서는 안된다. 데이터베이스 공유자원의 영구 락 해제를 finalizer나 cleaner 에 맡겨놓으면 시스템 전체가 서서히 멈출 수 있다.
객체 소멸자의 위험성
finalizer와 cleaner는 심각한 성능 문제를 동반한다. 이 방식은 일반적인 자원 해제에 사용하는 AutoCloseable 인터페이스의 close 메서드 구현방식 대비 수십~수백배의 성능 저하를 가져온다.
finalizer는 심각한 보안 문제도 가지고 있다. 객체생성 또는 직렬화 과정에서 예외가 발생하면 생성되다 만 객체의 하위 클래스에서 finalizer 가 수행될 수도 있다. final 클래스들은 하위 클래스를 만들 수 없으니 이 공격에서 안전하지만, final 이 아닌 클래스의 경우 우 아무일도 수행하지 않는 finalize 메서드를 final 로 선언해서 공격을 막을 수 있다.
finalizer 와 cleaner 대체안
파일이나 스레드 등 종료해야 할 자원에 대해서는 자원의 정리를 명시해 주어야 한다. finalizer, cleaner 대신에 AutoCloseable 인터페이스의 close 메서드를 구현해주면 된다. 클라이언트에서는 인스턴스를 다 쓰고나서 close 메서드를 호출해 주어야 한다. close 메서드의 명시적 호출보다는 try-with-resource 구문을 사용하는게 더 좋다.
finalizer 와 cleaner 는 어디에 쓰는 것일까?
그럼 자바의 객체 소멸자는 대체 어디에 사용해야 할까? 첫 번째는 자원의 소유자가 AutoCloseable.close 메서드를 호출하지 않는 것에 대비한 안정망 역할로 사용할 수 있다. 자바 라이브러리의 FIleIn/OutputStream, ThreadPoolExecutor 클래스는 안전망 역할의 finalizer 소멸자를 제공한다.
두 번째 예는 네이티브 피어와 연결된 객체에서 쓰인다. 네이티브 피어란 일반 자바 객체가 네이티브 메서드를 통해 기능을 위임한 네이티브 객체를 말한다. (JNI - 하드웨어 또는 운영체제 종속 프로그램, C, C++, 어셈블리 언어로 작성된 라이브러리의 호출 인터페이스) 자바 피어를 회수할 때 네이티브 객체를 회수하기 위해 소멸자를 활용할 수 있다.
정리
이번 아이템에서는 조금 깊은 개념을 다뤘다. 전공수업때 배운 자바언어 실행원리를 복습하는 느낌이랄까... AutoCloseable 인터페이스의 중요성을 한 번 더 짚었다는 생각으로 정리된 것 같다.
'프로그래밍 > Effective Java' 카테고리의 다른 글
아이템 10. equals는 일반 규약을 지켜 재정의하라 (0) | 2024.07.07 |
---|---|
아이템 9. try-finally 보다는 try-with-resources 를 사용하라 (0) | 2024.07.07 |
아이템 7. 다 쓴 객체참조를 해제하라 (0) | 2024.07.07 |
아이템 6. 불필요한 객체 생성을 피하라 (0) | 2022.02.24 |
아이템 5. 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 (0) | 2022.01.25 |
- Total
- Today
- Yesterday