- 초기 단계의 자바에서는 I/O를 처리하기 위해 java.io 패키지에 있는 클래스를 제공했다.
- 바이트 기반의 데이터를 처리하기 위해 여러 종류의 Stream이라는 클래스를 제공한다.
- char 기반의 문자열로만 되어있는 파일은 Reader/Writer를 사용한다.
자바에서 데이터 입출력은 Stream을 통해 이루어진다. 프로그램을 기준으로 들어오면 Input(읽기), 내보내면 Output(쓰기)로 방향을 결정하고, 데이터의 교환을 위해서는 Input과 Output을 모두 만들어야 한다. 입출력과 관련된 모든 작업은 java.io 패키지에서 제공하고 있다.
Java I/O PROCESS
문제점
NIO.2 API
가 추가되었다.Channel
과 Buffer
를 사용한다.public void writeFile(String fileName, String data) throws Exception {
FileChannel channel = new FileOutputStream(fileName).getChannel();
byte[] byteData = data.getBytes();
ByteBuffer buffer = ByteBuffer.wrap(byteData);
channel.write(buffer);
channel.close();
}
구분 | IO | NIO |
---|---|---|
입출력 방식 | 스트림 | 채널 |
버퍼 방식 | 넌버퍼(Non-Buffer) | 버퍼(Buffer) |
비동기 방식 | 지원 안 함 | 지원 |
블로킹 / 넌블로킹 방식 | 블로킹 방식만 지원 | 블로킹 / 넌블로킹 방식 지원 |
1. Channel
IO에서는 데이터를 읽기 위해서 입력 스트림을 생성하고 출력하기 위해 출력 스트림을 생성해야 했지만 채널에서는 입력과 출력을 위해 별도의 채널을 만들 필요가 없다.
NIO는 채널 기반으로 스트림과 달리 양방향으로 입력과 출력이 가능하며 쓰레드와 버퍼 사이에서 일종의 터널 역할을 해서 입출력 기능을 수행한다.
2. Buffer
기존 IO에서도 Buffer로 한꺼번에 입력받고 출력하기 위해 BufferdInputStream과 같은 확장 클래스를 사용하기도 했는데
NIO에서는 기본적으로 버퍼를 사용해서 입출력을 하기 때문에 효율적으로 처리가 가능하고 데이터의 위치를 이동하면서 필요한 부분을 읽고 쓸 수 있다.
버퍼가 사용하는 메모리 위치에 따른 분류
구분 | Non-direct buffer | Direct buffer |
---|---|---|
사용하는 메모리 공간 | JVM의 힙 메모리 | 운영체제의 메모리 |
버퍼 생성 시간 | 빠르다 | 느리다 |
버퍼의 크기 | 작다 | 크다 |
입출력 성능 | 낮다 | 높다 |
Direct Buffer
운영체제에서 생성되므로 여러가지 처리가 필요해 속도가 느리다.
Channel
을 사용해서 버퍼의 데이터를 읽고 저장할 경우에만 운영체제의native IO
를 수행한다.
만약 Channel을 사용하지 않고 사용한다면 내부적으로 JNI를 호출해야 하기 때문에 오버 헤더가 추가된다.
NIO의FileChannel
과Direct Buffer
를 활용하면 자원 사용량을 줄일 수 있다.
3. Blocking / Non-Blocking
IO는 쓰레드가 Blocking이 되면 인터럽트도 발생시킬 수 없고 빠져나오기 위해서는 스트림을 닫아야만 한다.
하지만 NIO는 Blocking 시 인터럽트로 빠져나올 수 있고, Non-Blocking으로 입출력 작업 준비가 완료된 채널만 선택할 수 있도록 지원해서
작업 중인 쓰레드가 Blocking 되지 않게 한다. 이때 사용하는 것이 Selector
이다.
Selector
네트워크 프로그래밍의 효율을 높이기 위해 도입된 것으로 한 개의 쓰레드로 다수의 채널을 처리할 수 있는 기술이다.
Selector에 여러 채널이 등록되면 쓰레드는 셀렉터에 등록된 채널 중에 가용한 채널이 있는지 알 수 있고 이런 방식을 멀티플렉싱(Multiplexing)
이라고 한다.
4. Scatter/Gather
시스템 콜을 여러 번 호출하는 비효율적인 작업을 개선하기 위해 Scatter
과 Gather
로 프로세스에서 사용한 버퍼 목록들을 한 번에 넘긴다.
즉, 운영체제에서 최적화된 로직에 따라 버퍼들을 순차적으로 처리해 데이터를 읽고 쓸 수 있다.
5. 가상 메모리
프로세스 내 버퍼의 가상 주소와 커널 영역 버퍼의 가상 주소가 같은 물리 메모리를 참조하게 매핑시켜 데이터 복사 작업을 생략할 수 있다.(CPU blocking 대기 시간 X)
해당 OS 기술은 Zero-copy
라고 부른다.
6. File lock
한 프로세스가 어떤 파일에 락을 획득했을 때 다른 프로세스가 해당 파일을 동시에 접근하지 못하게 제한하는 기능이다.
기존 IO의 속도와 Blocking으로 인한 성능 저하를 개선하기 위해서 여러가지 방식을 도입했습니다.
하나의 채널로 다수의 입출력 작업을 수행할 수 있고 버퍼를 사용하여 속도를 개선했으며,
Non-Blocking 방식을 지원하면서 Selector를 이용하여 가용한 채널에 접근할 수 있습니다.
시간을 절약할 수 있고 데이터의 필요한 부분을 읽거나 쓸 수 있기 때문입니다. 데이터를 버퍼 공간에 담아놨다가 공간이 가득차면 데이터를 저장하기 때문에
사용하지 않을 때보다 시간을 절약할 수 있고 Buffer의 position을 이용해서 위치를 파악하면 필요한 부분의 데이터를 읽거나 쓸 수 있습니다.
운영체제 관점에서 버퍼를 사용하지 않았을 때 CPU Block이 계속해서 발생하기 때문에 속도가 느린데 버퍼를 사용하면 CPU 부하를 줄일 수 있습니다.
IO를 선택하겠습니다. 파일 다운로드 시에는 데이터를 읽어야만 저장할 수 있으므로 비동기적으로 처리해야 할 작업이 필요하지 않기 때문에 Non-Blocking으로 인한 추가 작업을 수행하지 않고 리소스를 절약하며 기능을 수행할 수 있을 것 같습니다.