8. finalizer 와 cleaner 사용을 피하라
finalizer 와 cleaner 는 자바의 두가지 객체 소멸자이다.
#
Cleaner- Java 9에서는 fianlizer가 deprecated 됐고 cleaner가 새로 생겼다.
- cleaner는 별도의 쓰레드를 사용해서 finalizer보다는 덜 위험하지만, 여전히 예측불가하고, 느리며 불필요하다.
#
finalizer 와 cleaner 의 문제점들- 예측이 어려움
- 일반적으로 불필요함
- 오동작, 낮은성능, 이식성 문제, 위험성
#
1. 즉시 실행된다는 보장이 없다.- 객체에 접근할 수 없게 된 후 finalizer / cleaner 의 수행시점을 알 수 없다.
- finalizer / cleaner 의 수행은, 전적으로 GC 알고리즘에 달렸다.
- finalizer 스레드는 다른 애플리케이션 스레드보다 우선순위가 낮아 실행 기회를 제대로 얻지 못할 수 있다.
- cleaner 는 자신을 수행할 스레드를 제어할 수 있다.
#
2.수행 여부를 보장하지 않는다.데이터베이스 같은 공유 자원의 영구 Lock 해제를 finalizer 나 cleaner 에 맡겨 놓으면 분산 시스템 전체가 서서히 멈출것
- 상태를 영구적으로 수정하는 작업에서는 절대 의존해선 안된다.
#
3.finalizer 동작 중 발생한 예외는 무시된다.경고 조차 출력하지 않음.
잡지 못한 예외 때문에 해당 객체는 자칫 마무리가 덜 된 상태로 남을 수 있다.
Finalize를 실행하는 동안 catch되지 않는 예외가 발생하면 예외가 무시되고, Finalize가 끝난다.
이로인해 객체가 망가질 가능성이 있고, 다른 스레드에서 해당 객체에 접근하면 문제가 생긴다.
cleaner 를 사용하는 라이브러리는 자신의 스레드를 통제하기 때문에 이런 문제가 없다.
#
4. 심각한 성능 문제GC 의 효율을 떨어 뜨린다.
#
5. finalizer 공격에 노출되어 심각한 보안 문제finalizer 공격 원리
- 생성자나 직렬화 과정에서 예외가 발생하면, 생성 되다만 객체에서 악의적인 하위 클래스의 finalizer 가 수행될 수 있다.
악의적인 하위 클래스의 finalizer
- finalizer 는 정적 필드에 자신의 참조를 할당하여 GC 가 수집하지 못하게함
객체 생성을 막으려면 생성자에서 예외를 던지는 것만으로 충분하지만, finalizer 가 있다면 그렇지 않다.
- final 클래스는 하위 클래스를 만들수 없으니 finalizer 공격에서 안전함.
- final 클래스가 아니면, 아무일도 하지 않는 finalize 메서드를 만들고 final 로 선언하자.
?? 실제 finalizer 공격이 발생한 사례가 무엇이 있을까?
#
finalizer / cleaner 의 대안#
1.AutoClosable 의 구현예외가 발생해도 제대로 종료할 수 있게 처리해주는 try-with-resouces를 사용하는 것이 좋다.
#
2. 클라이언트에서 인스턴스를 다 쓰고나면 close 메서드 호출예외가 발생해도 제대로 종료되도록 try-with-resources
를 사용 9
#
3. 인스턴스 자신이 닫혔는지 추적하기- close 메서드에서, 객체가 유효하지 않음을 필드에 기록한다.
- 다른 메서드는 이 필드를 검사해서 객체가 닫힌 후 불렸다면 IllegalStateException 을 던진다.
?? 2 번의 방법은 어떻게 쓰이는 것일까? 얼마나 쓰일까?
#
finalizer / cleaner 의 쓰임새#
1. 클라이언트가 하지 않은 자원회수를 늦게라도 해주는게 낫다.FileInputStrean, FileOutputStream, ThreadPoolExecutor 가 대표적으로 안전망 역할의 finalizer 를 제공함.
#
2. 네이티브 피어와 연결된 객체#
Native Peer- 일반 자바 객체가 네이티브 메서드를 통해 기능을 위임한 네이티브 객체
- 네이티브 피어는 자바 객체가 아니니 GC 는 존재를 알지 못하여 회수하지 않음
#
조건- 성능저하를 감당할 수 있어야 한다.
- 네이티브피어가 심각한 자원??을 가지고 있지 않아야 한다.
#
close 메서드의 사용- 성능저하를 감당할 수 없는 경우
- 네이티브 피어가 사용하는 자원을 즉시 회수해야 할 경우
#
3. cleanercleaner 는 사용하기에 조금 까다롭다.
Room 클래스로 이 기능을 설명하고 있다.
- room 을 수거하기 전, 반드시 clean 청소 해야 한다.
- Room 클래스는 AutoCloseable 을 구현한다.
- 자동 청소 안전망이 cleaner 를 사용하지 말지는 내부 구현 방식에 관한 문제다.
- finalizer 와 달리 cleaner 클래스의 public API 에 나타나지 않는다. ??
cleaner 를 안전망으로 활용하는 AutoCloseable 클래스
클라이언트가 모든 Room 생성을 try-with-resources
블록으로 감쌌다면 자동 청소는 전혀 필요하지 않다.
System.out.println("방 청소");
가 같이 실행 될 것이다.
만약 try-with-resources
블록 이 없다면,
System.out.println("방 청소");
가 출력되지 않을 수 있다.
clean 의 예측할 수 없는 특징 때문이다.