개발/Java

[Java] Java IO 에 대해서

hojak99 2017. 8. 8. 21:02

Java IO 는 예전부터 많이 느리다는 이야기가 있었다. 하지만 내부적으로 어떻게 동작하는지는 대충 알고 있었기 때문에 좀 더 자세히 알아야 할 필요가 있을 것 같다. 


 우선 Java IO 는 OS에서 관리하는 커널 버퍼에 직접 접근할 수 없으며, Blocking IO 이기 때문에 매우 비효율적이다. 



모 블로그에서는 기존 자바 IO에서는 커널 버퍼를 직접 접근하는 Direct Buffer 를 핸들링 할 수가 없다고 한다. 그래서 소켓이나 파일에서 stream 이 들어오면 커널 버퍼에 쓰여지게 되는데 Code 상에서 접근 할 수 있는 방법이 없었기 때문이라고 한다. 그래서 JVM 이 JVM 내부의 메모리에 불러온 후에 이 데이터에 접근 할 수 있었는데 바로 이때 오버헤드가 발생해 느리다는 것이다. 


기존의 Java IO 는 다음과 같이 파일을 읽는다고 한다.

1. JVM 이 파일을 읽기 위해 커널에 명령을 전달한다.

2. 커널은 시스템 콜 (read()) 를 사용한다.

3. 디스크 컨트롤러가 물리적 디스크로부터 파일을 읽는다.

4. DMA 를 이용해 커널 버퍼로 복사한다.

5. JVM 내부 버퍼로 복사한다.


[여기서 DMA 란 Direct Memory Access 를 말하는데 CPU의 입출력 명령 하나에 의해 CPU를 거치지 않고 일련의 정보를 곧바로 입출력 장치에서 메모리 or 메모리로부터 입출력 장치에 전달하는 기술이다.]


즉 위와 같은 과정을 겪으면서 JVM 내부 버퍼에 복사할 때 CPU가 관여되며 복사 버퍼는 사용하고 GC 대상이 되며 복사가 진행 중인 동안 IO 를 요청한 쓰레드는 Blocking이 된다는 것이다.


우선 여기서 헷갈릴 수도 있는게 물리적 디스크에서 커널 영역으로 복사하는 것은 DMA 의 도움으로 CPU가 관여하지 않기 때문에 오버헤드가 적다는 것이다. 하지만 JVM 내부 버퍼로 복사할 때는 CPU가 관여한다.




그래서 NIO 를 사용해야 한다고 한다. 

NIO는 Java IO에서 JVM 내부 메모리로의 복사 문제를 해결하기 위해 커널 버퍼에 직접 접근할 수 있는 클래스를 제공한다. NIO가 제공하는 버퍼들 중 Direct Buffer 는 ByteBuffer 만 지원한다고 한다. 그래서 커널 버퍼를 직접 사용하고 싶다면 불편하더라도 Byte Buffer 만을 사용해야 한다고 한다.

반응형