Effective Java 2장 객체의 생성과 삭제
규칙 7. 종료자 사용을 피하라
종료자(finalize)를 사용한다면?
예측불가능하며 불필요함.
종료자의 경우 수행되기 까지 시간이 걸릴 수 있기 때문에 되도록 긴급한 작업은 종료자 안에서 처리하지 않는 것이 좋음.
종료자로 인해 객체 메모리 반환이 지연되는 경우도 생길 수 있음.
(ex) 파일을 종료자 안에서 닫을 때 치명적임. JVM은 종료자를 천천히 실행하므로 열린 상태의 파일이 많이 남아있을 수 있음.
종료자를 사용하면 성능면에서도 심각하게 떨어질 수 있음.
데이터베이스와 같은 공유자원에 대한 중요 상태 정보들을 종료자로 갱신하면 안됌.
대안
종료자보단, 명시적 종료메서드를 사용(객체 종료를 보장하기 위해 보통 try-catch문과 자주 쓰임.)
Foo foo = new Foo();
try{
...
} finally{
foo.terminate(); // 명시적 종료메소드
}
- 사용하지 않는 객체에 대해 클라이언트가 명시적 종료메소드를 호출하도록
- 클래스 내 종료여부를 저장할 수 있는 변수를 두고, 모든 메소드에서 이를 체크해, 종료된 객체를 통해 메소드를 호출할 시 IllegalStateException이 던져지도록 처리
그럼에도, 종료자는 언제 사용하는 것이 좋을까?
1. 명시적 종료 메소드 호출을 잊을 경우에 대비한 안전망
- 해당 자원을 발견하게 될 경우, 반드시 경고성 log를 남겨야 함. 코드 버그가 있는 것이므로.
2. 네이티브 피어와 연결된 객체를 다룰 경우
네이티브 피어 - 네이티브 메서드를 통해 기능 수행을 위임하는 네이티브 객체
- 네이티브 피어의 경우, 일반 객체가 아니기 때문에 GC 가 알 수 없다. 자바 측 피어 객체가 반환될 때 함께 반환되기도 어렵기 때문에, 이 네이티브 피어가 중요자원을 점유하고 있지 않은 이상은 종료자를 통해 반환하는 것이 적합하다.
- 즉시 종료해야 하는 자원을 포함할 경우엔 명시적 종료 메서드를 클래스에 추가하는 것이 필요함.
주의점
종료자 연결(finalizer chaining)
@Override protected void finalize() throws Throwable{
try{
.. // 하위클래스 종료자 호출.
}finally{
super.finalize();
}
}
- 하위클래스가 상위클래스의 종료자를 재정의 하는 상황
- 하위클래스의 종료과정에서 예외가 발생해도, 상위클래스의 종료자를 반드시 호출하게끔 만들기 위함.
종료보호자 패턴
- 종료되어야 하는 객체의 클래스 안에 종료자를 정의하는 대신, 익명클래스 안에 종료자 정의
public class Foo {
// 이 객체의 경우, 바깥 객체를 종료시키는 역할만 함.
private final Object finalizerGuardian = new Object(){
@Override protected void finalize() throws Throwable(){
...// 바깥 Foo 객체 종료시킴.
}
}
}
- 바깥 객체의 모든 참조가 사라지는 순간, 종료보호자의 종료자도 실행가능한 상태가 되어, 마치 Foo객체의 종료자인 것처럼 수행됌.
'공부 > JAVA' 카테고리의 다른 글
이펙티브 자바 3장 규칙 9. equals를 재정의할 때는 반드시 hashCode도 재정의하라 (0) | 2021.02.17 |
---|---|
이펙티브 자바 3장 규칙 8. equals 를 재정의할 때는 일반규약을 따르라 (0) | 2021.02.17 |
이펙티브 자바 2장 규칙 6. 유효기간이 지난 객체참조는 폐기하라 (0) | 2021.02.17 |
이펙티브 자바 2장 규칙 5. 불필요한 객체는 만들지 말라 (0) | 2021.02.17 |
이펙티브자바 2장 규칙4. 객체생성을 막을 때는 private 생성자를 사용하라 (0) | 2021.02.17 |
댓글