반응형
안녕하세요 돼지왕왕돼지입니다.
오늘은 finalizer (파이널라이저) 사용을 피하자. 라는 주제로 이야기를 해볼까 합니다.
이 글은 "Effective Java" 를 기반으로 작성하였습니다.
Finalizer 왜 피해야 하는가?
- Finalizer 는 예측 불가에다가 위험하기도 하며 일반적으로 불필요하다. 파이널라이저를 사용하면 예측이 어려운 프로그램 실행과 성능 저하 및 이식성의 문제가 생길 수 있다.
파이널라이저의 문제점
- 신속하게 실행된다는 보장이 없다.
객체가 사용할 수 없게 되는 시점부터 파이널라이저가 실행되는 시점까지는 긴 시간이 소요될 수 있다.
즉! 실행시간이 중요한 작업을 "절대!" 하지 말아야 한다는 것. ( ex) finalizer 에서 파일 닫기 )
- Finalizer 의 수행 속도와 수행 타이밍은 G.C. Algorithm 에 따라 다르다.
따라서 클래스에 파이널라이저를 사용하면 간혹 인스턴스들의 메모리 회수와 재활용이 지연될 수 있고, OutOfMemoryError 가 생기기도 한다.
- 자바의 명세에서도 파이널라이저가 신속하게 실행된다는 보장이 없는 것은 물론 반드시 실행될 것인지도 보장하지 않는다.
그렇다고 이런걸 쓰지 말아라.
- System.gc 와 System.runFinalization 메소드들을 사용하지 말자.
이 메소드들은 파이널라이저가 실행될 가능성을 높여줄 뿐, 반드시 실행됨을 보장하지는 못한다.
- Finalize 를 보장하는 메소드들은 System.runFinalizersOnExit 와 Runtime.runFinalizersOnExit 가 유일한데,
치명적인 결함이 발견되어 현재는 사용이 금지되었다.
Finalizer 의 문제는 이것뿐일까?
- Finalizer 에서는 Exception 도 무시해버린다. 심지어 경고조차 출력하지 않는다.
- Finalizer 를 사용하면 엄청난 성능 저하가 발생한다. ( 無 : 5.6ns, 有 : 2,400ns. )
그럼 Finalizer 대신 무엇을 이용해야 할까?
- 작업이나 자원을 정상적으로 종료하는 메소드를 추가하고 수행시켜준다. ( ex) Cursor.close, InputStream.close )
한 가지 고려할 것은 종료 여부를 유지 관리해주어야 한다는 것. 유효하지 않음을 private 필드로 기록하고,
종료된 이후에 호출이 되면 IllegalStateException 을 반환해야 한다.
- 위의 종료 메소드들은 보통 try{} finally {} 구문을 통해 finally 에서 처리해주는 것이 좋다.
그럼 Finalizer 는 "무조건" 쓰지 말아야 하나?
- 다음과 같은 경우에서는 쓸 "수" 는 있다.
1. 생성된 객체를 갖고 있는 코드에서 그 객체의 종료 메소드 호출을 빠뜨렸을 경우의 "안전망"으로서의 역할
늦게라도 호출되어 자원을 해지하는 것이 안 하는 것보다는 낫기 때문에.... 추가로 메세지를 출력하면 좋다. ( 경고 )
2. Native Peer ( 네이티브 피어 ) 와 관련된 작업 수행시..
네이티브 메소드를 통해 일반 자바 객체가 자신의 일을 위임하는 네이티브 객체가 네이티브 피어인데..
일반 자바 객체가 아니므로, 그것이 소멸되었을 때 G.C. 를 해야하는지 모른다.
이 때 finalizer 에서 처리해주며, 이 때!!! 마찬가지로 중요한 자원을 갖지 않고, 타이밍 문제가 없을 때 사용한다.
Finalizer 쓸 때 추가적인 주의사항은 없나?
- 있다. Finalizer 의 Chaining 은 자동으로 실행되지 않는다.
어떤 클래스가 파이널라이저 메소드를 갖고 있고, 서브 클래스에서 그 메소드를 오버라이드 한다면, 서브 클래스의 파이널라이저에서 슈퍼 클래스의 파이널라이저를 반드시 호출해주어야 한다. 아래와 같이..
@Override
protected void finalize() throws Throwable{
try{
... // finalize code들.
}
finally{
super.finalize();
}
}
- 위의 방법도 좋지만, 실수로 빼먹을 가능성이 높다.
이 때를 대비해 Finalizer Guardian ( 파이널라이저 가디언 ) 을 쓰는 것이 좋다.
public class Foo{
private final Object finalizerGuardian = new Object(){
@Override
protected void finalize() throws Throwable{
... // finalize 코드
}
}
}
객체가 소멸될때 자동 finalize 를 수행하기 때문에 훨씬 안전하다.
로그인 없이 추천 가능합니다. 손가락 꾸욱~
반응형
'프로그래밍 놀이터 > 디자인 패턴, 리펙토링' 카테고리의 다른 글
[Design Pattern/Java] equals 메소드를 오버라이드 할 때는 hashCode 메소드도 항상 같이 오버라이드 하자. (4) | 2012.02.22 |
---|---|
[Design Pattern/Java] Equals 메소드를 오버라이딩 할 때는 보편적 계약을 따르자. (0) | 2012.02.22 |
[Design Pattern/Java] 쓸모 없는 객체 참조를 제거하자. (0) | 2012.02.10 |
[Design Pattern/Java] 불필요한 객체의 생성을 피하자. (0) | 2012.02.10 |
[Design Pattern/Java] private 생성자를 사용해서 인스턴스 생성을 못하게 하자. (0) | 2012.02.10 |
댓글