파이널라이즈는 우선순위가 낮다. 따라서 객체의 반환시점에 의존된 프로그램은 메모리 회수와 재활용 부분에서 문제가 될 수 있고 이는 시스템 지연으로 발생하게 된다. 신속하게 실행되지 않음과 실행 보장을 하지 않음이 자바 문서에 명시되어 있다.
따라서 파이널 라이즈가 실행되지 않은채 프로그램이 종료될 수 있고, 영속적인 상태를 변경하기 위해 사용해서는 안 된다.
파이널라이즈를 하는 동안 catch하지 못한 예외가 발생하게 되면, 이 예외는 무시되고, 그 객체의 파이널라이즈는 종료된다. 이렇게 되면 객체는 불완전한 상태가 된다. 일반적으로 예외가 발생하면 스레드 실행이 종료되고 예외메시지가 발생되는데 파이널라이저는 예외가 무시되기 때문에 예외가 발생했음을 알 수가 없다.
파이널라이저는 속도가 매우 느린 단점이 있다. 자원 반환 작업이 필요한 경우인 파일이나 스레드 등 종료가 필요한 작업의 경우엔, 파이널라이저보다 작업이나 자원을 정상적으로 종료하는 메서드만 별도로 추가하면 된다.
각 인스턴스에서 자신의 종료여부를 유지 관리를 고려해야하는데, 종료 메서드에서는 해당 객체가 유효하지 않다는 것을 private를 이용해서 기록해야한다. 또한, 해당 객체가 종료되면 다른 곳에서는 IllegalStateException 예외를 발생시켜야한다.
예를 들면, inputStream/outputStream의 close 메소드가 있고, 이 종료 메서드들은 try-finally를 사용해서 확실하게 실행되도록한다. finally 블록에 호출된 메서드는 반드시 실행됨을 보장한다.
파이널라이저는 생성된 객체를 갖고 있는 코드에서 그 객체의 종료 메소드 호출을 보장한다. 클라이언트가 종료 메서드의 호출에 실패하는 경우를 대비해서 사용해서 경고메세지를 보여줘야한다. 자원이 반환되지 않을 것을 우려해서 만드는 대비책이지만 파이널라이저 코드상에 파이널라이저를 쓰지 않도록 하는 것이 더 중요하다.
네이티브피어는 네이티브메소드를 통해 일반 자바 객체가 자신의 일을 위임하는 네거티브객체를 의미한다. 일반적인 자바 객체가 아니기 때문에, 연관된 자바 피어 객체가 소멸되고 나서 네거티브 객체의 존재 여부를 파악하기가 쉽지 않으므로 별도의 종료메소드가 필요하다. 이 종료메소드는 자원 반환에 필요한 일들을 처리하고 네이티브메소드, 자바메소드에서 네이티브메소드를 호출하는 등 여러가지 형태로 사용될 수 있다.
~~
@Override
protected void finalize() throws Throwable {
try {
super.finalize();
} finally {
super.finalize();
}
}
~~
파이널라이저는 자동으로 실행되지 않기 때문에 호출을 꼭 해줘야한다.
일반 클래스가 파이널라이저를 갖고 있는 상황에서,
서브 클래스가 그 클래스를 오버라이드 한다면
서브클래스의 파이널라이저에서 수퍼클래스의 파이널라이저를 반드시 호출해야한다.
해야하는 이유는 서브클래스에서 파이널라이저 실행중에 오류가 생기더라도 수퍼클래스에서 실행하기 때문에 파이널라이즈될 수 있다.
자신을 포함한 외부클래스의 인스턴스를 파이널라이즈 하는 목적만을 갖는 익명의 내부 클래스에 파이널라이저
익명의 내부 클래스 인스턴스는 자신을 포함하는 외부 클랫의 각 인스턴스당 하나씩 생성된다.
외부클래스 인스턴스는 자신의 파이널라이저 가디언 객체 참조를 private 인스턴스 필드에 보존한다. 따라서 외부 클래스 인스턴스와 동시에 실행되게 된다.
public class Foo {
private final Object finalizerGuardian = new Object() {
@Override
protected void finalize() throws Throwable {
super.finalize();
}
}
}
effecitive java ed.2
내용 이해가 어려워 정확하지 않은 내용이 있을 수 있습니다.
댓글로 알려주세요!