/** 
Garbage Collector를 이용한 finalize()호출 I 
**/ 
import java.io.*; 
class FinalMan{ 
    private FileWriter fw = null; 
    public FinalMan(String filename) throws IOException{ 
        this.fw = new FileWriter(filename); 
    } 
    public void writeData(String str) throws IOException{ 
        this.fw.write(str); 
    } 
    protected void finalize() throws Throwable, IOException{ 
        if (this.fw != null){ 
            this.fw.close(); 
        } 
        System.out.println("finalize()의 파일 닫기");         
        super.finalize(); 
    }  
} //end of FinalMan 

public class FinalManMain{ 
    public static void main(String[] args) throws Exception{ 
        System.out.println("프로그램 시작"); 
        //단순블럭 
        { 
            FinalMan fm = new FinalMan("finalize.dat"); 
            fm.writeData("안녕하세요"); 
            fm.writeData("Hello"); 
            fm = null; 
        } 
        System.gc();//가비지 콜렉터 구동 
        System.out.println("프로그램 종료"); 
    } //end of main 
} //end of FinalManMain class 
//㉶------------------------------------------------------------------㉳ 
/*** 
C:javasrcchap10>javac FinalManMain.java 
C:javasrcchap10>java FinalManMain 
프로그램 시작 
finalize()의 파일 닫기 
프로그램 종료 
***/

 

위의 예에서 FinalMan의 생성자에서 매개변수로 주어진 파일명으로 FileWriter를 생성하고 있습니다.  

◈ private FileWriter fw = null; 
◈ public FinalMan(String filename) throws IOException{ 
◈         this.fw = new FileWriter(filename); //문자 파일 스트림 생성 
◈ } 

그리고 FileWriter fw를 이용해서 주어진 문자열을 파일에 기록하는 메서드를 포함하고 있습니다. 

◈ public void writeData(String str) throws IOException{ 
◈        this.fw.write(str); //스트림을 이용해서 파일에 문자열 기록 
◈ } 

그런데 이상한 것이 있습니다. 데이터를 기록하기 위해서는 writeData()를 호출하면 되지만 FinalMan 어디에도 생성된 스트림을 닫아주는 곳은 없습니다. 즉 위의 FinalMan 클래스에서 보여주고자 하는 것은 FinalMan의 객체가 더 이상 쓸모가 없을 때 호출되는 finalize()에 스트림을 닫아주고자 하는 것입니다. 어차피 가비지 콜렉터에 의해서 finalize()가 호출될 것이고 객체가 소멸되기 전까지는 스트림을 닫지 않겠다는 것입니다. 

▣ finalize()의 재정의  
◈ protected void finalize() throws Throwable, IOException{ 
◈         if (this.fw != null){ 
◈             this.fw.close(); 
◈        } 
◈         super.finalize(); 
◈    }  

가비지 콜렉터에 의해서 객체가 소멸되면서 FinalMan의 finalize()가 호출될 것이며, 자동으로 스트림을 닫는 작업과 상위 클래스의 finalize()를 호출하는 작업이 이루어지는 것입니다. 

finalize()가 호출되는 것을 보장하기 위해서 독특한 방법을 이용하고 있습니다. 단순히 블록 처리를 하고 블록 내에서 객체를 만들고 있습니다. 그리고 블록 내에서 생성된 객체를 null로 초기화하고 있습니다. 이렇게 되면 생성된 객체가 블록 내부의 지역 변수가 되기 때문에 블록이 끝나면 가비지 콜렉터의 수집 대상이 되는 것입니다. 엄밀하게 말하면, 지역적으로 생성된 객체의 참조값이 다른 곳에서 사용되지 않는다는 것이 보장되면 가비지 콜렉터의 수집대상이 되는 것입니다. 

◈ { 
◈        FinalMan fm = new FinalMan("finalize.dat"); 
◈        fm.writeData("안녕하세요"); 
◈        fm.writeData("Hello"); 
◈        fm = null; 
◈ } 

가비지 콜렉터의 수집 대상이 되도록 만드는 것은 아주 중요합니다. 특정 블록 내에서 생성된 객체의 참조값을 다른 곳에서 사용하지 않는다는 것을 보장하기 위해서 블록 내에서 생성된 객체의 참조값을 null로 초기화하고 있습니다. 이 구문이 바로 참조값을 사용하지 않겠다고 보장하는 구문이 되는 것입니다.  

▣ null의 초기화 여부 
◈ 보통의 경우 사용하지 않는 참조값일 경우 가비지 콜렉터가 알아서 하기 때문에 별로 신경 쓰지 않는다. 하지만 사용자가 사용하지 않는 객체를 null로 명시화하면 프로그램은 더욱 유연하게 동작한다. 

가비지 콜렉터는 메모리가 부족하거나 메모리의 청소가 필요할 때 자동으로 구동되는 가상머신의 시스템 스레드입니다. 보통 이 스레드를 Finalizer라고 칭합니다. 필요에 의해서 Finalizer 스레드가 동작하지만 사용자가 직접 Finalizer를 구동하고자 한다면 다음과 같은 구문을 사용하면 됩니다. 

◈ System.gc(); 

지역적으로 선언된 객체가 더 이상 참조값을 사용하지 않는다는 것이 보장되었으며, Finalizer까지 구동되었다면, 지역적으로 선언된 객체 FinalMan fm의 finalize()가 호출되는 것을 확인할 수 있을 것입니다.


출처 : http://www.softpackage.com/bbs/bbs/content.asp?grp=devforum&board=java&num=104&opt=

+ Recent posts