5월, 2015의 게시물 표시

[자바] FileChannel에서 map을 하면 내부적으로 unmap은 언제 일어날까? Finalizer를 PhantomReference가 대체할 수 있나?

1. java.nio.FileChannel에서 map을 호출한 다음에 unmap은 언제 이루어질까?

언뜻 생각해보면 FileChannel에서 mmap을 호출하므로 FileChannel을 close할 때 명시적으로 unmap을 해주는 게 효율적인 구현이 아니었을까 생각이 들긴 합니다..
하지만, 실제 JDK 구현은 그렇게 하지 않았습니다.

openjdk v6 코드를 보면
{openjdk6}/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java 에 해당 구현이 되어 있습니다.

channel을 close하면 내부적으로 implCloseChannel 메소드가 호출이 되는데 여기에서는 mmap 관련한 일은 행하지 않습니다.
명시적으로 unmap을 하는 경우는 transferTo나 transferFrom이 호출된 경우 일시적으로 사용된 mmap을 바로 munmap해줍니다.

실제 MappedByteBuffer는 Unmapper라는 unmap을 위한 객체를 매번 따로 만들어서 해당 MappedByteBuffer에 대한 참조가 없으면 PhantomReference 방식으로 청소를 해줍니다.

코드를 쫓아가보면 결과적으로
{openjdk6}/jdk/src/share/classes/sun/misc/Cleaner.java 객체에 Unmapper 객체를 넘겨주는 형태입니다.

그냥 MappedByteBuffer 클래스에 finalize() 메소드를 구현하지 않고 PhantomReference 방식으로 복잡하게 처리한 것은 finalize() 메소드를 호출하는 Finalizer 쓰레드의 오버헤드를 줄이기 위한 것으로 보입니다. Finalizer 쓰레드에서 JNI 통해 munmap 시스템 콜을 하는 게 부담스러웠던 것입니다.

다시 문제로 돌아가서 왜 file channel을 close할 때 unmap을 하지 않았을까 생각해보면
원래 유닉스 시스템 콜에서도 fd를 close() 하는 것과 파일의 영역을 가상 메모리에 매핑한 것을 해지하는 munma…