finalizer와 cleaner 사용을 피하라
자바에서는 finazlier와 cleaner라는 두 가지 객체 소멸자를 제공한다.
이 두 가지의 객체 소멸자는 C++의 파과자( destructor )와는 다른 개념이다.
C++의 파괴자 같은 경우에는 특정 객체 와 관련된 자원을 회수하는 보편적인 방법이며, 자바 같은경우 try-with-resource와 try-finally를 이용하여 해결한다.
finalizer와 cleaner의 공통적인 문제점
이 둘의 공통적인 문제점은 객체의 접근 할 수 없게 된 후 finalizer와 clenaer가 실행되기까지 얼마나 걸릴지 알 수 없다.
즉 finalizer와 clenaer로는 제때 실행되어야 하는 작업을 할 수 없다.
예를 들어 파일 닫기같은 작업을 이 둘에게 맡기면 중대한 오류를 일으킬 수 있다. ( 시스템에서 동시에 열 수 있는 파일 개수에 한계가 있기 때문 )
또 finalizer와 cleaner가 얼마나 신속히 수행할지는 전적으로 가비지 컬렉터 알고리즘에 달려있으며 가비지 컬렉터마다 천차만별 이다.
finalizer
finalizer는 예측할 수 없고, 상황에 따라 위험할 수 있어 일반적으로 불필요하다. 또 오작동, 낮은 성능, 이식성 문제의 원인이 되기도 한다.
그래서 자바 9에서는 finalizer를 사용 자제(deprecated) API로 지정하였고 그 대안으로 cleaner를 소개했다.
cleaner
finalizer보다는 조금 더 낫지만 여전히 느리고 실행 시점을 예측할 수 없다.
finalizer와 cleaner를 대체할 AutoClose
fainzlier와 cleaner를 사용하는대신, AutoCloseable을 구현해주고 클라이언트에서 인스턴스를 다 쓰고 나면 close 메서드를 호출해주면 된다.
이 작업은 try-with-resource문을 사용하면 자동으로 close 메서드를 호출 해준다.
또한 인스턴스는 자신이 닫혀있는지 추적을 하는것이 좋으며 close메서드에서 이 객체는 더이상 유효하지 않음을 기록하고, 다른 메서드는 이 필드를 검사해서 객체가 닫힌 후에 불렸다면 IllegalStateException예외를 던진다.
finazlier와 cleaner의 사용 용도
자원의 소유자가 close 메서드를 호출하지 않는 것에 대비한 안정망 역할
fainlizer와 cleaner가 즉시 실행할 보장은 없지만 클라이언트가 하지 않은 자원 회수를 늦게라도 해주기 위해 사용
일부 자바 라이브러리(FileInputStream, FileOutputStream, ThreadPollExecutor) 에서는 이러한 용도로 사용 중 이다.
네이티브 피어와 연결된 객체에서 사용
네이티브 피어란 일반 자바 객체가 네이티브 메서드를 통해 기능을 위임한 네이티브 객체를 말한다.
네이티브 피어는 자바 객체가 아니니 가비지 컬렉터는 그 존재를 알지못해 자원을 회수하지 못하므로 cleaner나 fianlizer가 직접 나서서 처리하기에 적당한 작업이다. 하지만 이 때 역시 fianlizer와 cleaner가 언제 실행 될 지 모르니 즉시 자원을 회수 해야한다면 close메서드를 사용해야한다.
cleaner는 안정망 역할이나 중요하지 않은 네이티브 자원 회수용으로만 사용하는게 좋으며, 사용할때는 불확싱성과 성능 저하에 주의 해야한다.
'book review > Effective java' 카테고리의 다른 글
[Effective Java] Item 10. equals는 일반 규약을 지켜 재 정의하라 (0) | 2024.03.11 |
---|---|
[Effective Java] Item 9. try-finally보다는 try-with-resources를 사용하라 (0) | 2024.02.14 |
[Effective Java] Item 7. 다 쓴 객체 참조를 해제하라 (1) | 2024.02.07 |
[Effective Java] Item 6. 불필요한 객체 생성을 피하라 (0) | 2024.02.06 |
[Effective Java] Item 5. 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라. (0) | 2024.02.05 |