티스토리 뷰

자바의 객체 소멸자

 자바는 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 인터페이스의 중요성을 한 번 더 짚었다는 생각으로 정리된 것 같다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday