어떻게 이런 finalize( )를 쓰란 말이에요

Tags:

http://developers.sun.com/learning/javaoneonline/2005/coreplatform/TS-3281.html

자바의 finalize에 대한 내용입니다. 이 내용을 알면 당신도 자바 고수~

일단 상식적인 내용부터 시작하면..

1) finalize( ) 는 GC전에 호출될지 안될지 모른다. 언제 호출될지는 모른다.

2) finalize( ) 는 성능을 떨어뜨린다.

3) System.runFinalizersOnExit( )는 deprecated되었다. 가장 큰 이유는 rechable한 객체를 finalize를 하는게 말도 안된다는 것이고, 또다른 이유는 finalize의 순서가 보장안된다는데 있다.

자 다음부터 advanced된 내용입니다.

1) finalize를 실행하는 쓰레드는 애플리케이션을 실행하는 쓰레드와 별개이다. 따라서 single-threaded application에서도 synchornized가 필요할 수 있다. 이는 application과 finalize에서 동시에 xxx라는 자원을 접근한다고하면, 두개의 쓰레드가 xxx를 동시에 접근하게 된다. 이 문제를 해결하기 위해, 애플케이션의 비즈니스 로직을 담은 메소드내에서는 synchronized(xxx)를 해야하고, 물론 finalize안에서도 synchronized(xxx)를 해야합니다.

2) finalize는 어떤 메소드 foo( )내에 GC되려고 하는 객체에 대해 최종의 참조를 하고 있다면 그 시점에서 수행되버릴수 있다. 예를들어,

public long foo( … ) {

    return objRef.bar();
}    

와 같은 코드가 있을 때, objRef에 대한 bar( ) 호출 수행시, bar( )에서 this의 모든 final 변수만 접근가능하다고 하자. 그러면 bar( ) 호출시에 모든 final 변수를 캐싱한다음 this를 GC할 수 있다. 따라서, finalize가 this에 대해 수행될 수 있다. 만약 finalize가 수행된다면, this는 파괴된다. 그렇다면, 이 메소드는 분명히 실패할 것이다.

3) finalize는 자바 메모리 모델에 의해서 Write의 visibility만 보장한다. 이것이 의미하는 바는, Alpha와 같은 CPU를 쓰는 SMP상에서 잘못된 값을 read할 수 있다는 것이다. 따라서 제대로 된 값을 메인 메모리에서 읽어오기 위해서는 반드시 메모리 barrier를 넣어야하고, 자바에서는 베리어만 넣는 것이 불가능하므로, 어쩔 수 없이 뮤텍스를 통과시켜야한다.

결국 최종적인 ‘잘짠 finalize’는 다음과 같이 이루어진다.

void synchronized keepAlive( ) { }

public long foo( … ) {

    synchornized(공유자원) { // single-thread apps 라도 반드시!
    
        long result = objRef.bar();
    }
    
    keepAlive(); // this에 대한 최종 호출이 아니도록 만든다.
                 // 이를 통해 objRef.bar() 호출중 this의 파괴를 막는다.
    
    return result;
    
}

protected void fiinalize() {

    synchornized(this) { } // read visibility 확보

    synchornized(공유자원) { // single-thread apps 라도 반드시!
    
        자원정리
    
    }
}

Sun Developer Network 가입자에게 (물론 가입은 무료) java one이 무료 제공됩니다. 궁금하시면 링크 따라가서 직접 세미나 보실 수 있음..