Reactive Programmming

Java NIO - Direct Byte Buffer, Heap ByteBuffer

재심 2025. 1. 11. 18:24

Java 1.0에 포함된 Input/Output Stream에는 BufferedInputStream, BufferedOutputStream이라는 구현체가 있다.

내부적으로 버퍼를 사용하는데, 이 버퍼는 JVM Heap에 존재하는 버퍼이다.

 

그리고 실제로 리소스를 읽어오려면 커널 영역의 버퍼를 통해 복사를 해와야 하는데 이 과정에서 CPU 자원을 사용하게 된다.

반면 커널 영역의 버퍼를 바로 사용할 경우 Disk Controller에 의해 CPU 도움 없이 리소스를 버퍼로 바로 복사할 수 있다.

 

Java 1.4에서 등장한 Java NIO에서는 Channel과 Buffer를 통해 리소스와 통신을 하게 되며

ByteBuffer를 활용하는 경우 DirectByteBuffer, HeapByteBuffer 2가지로 제공한다.

특성 DirectByteBuffer HeapByteBuffer
메모리 위치 JVM 힙 메모리 네이티브 메모리 (JVM 힙 외부)
메모리 관리 GC가 관리 GC의 관리 범주가 아님. 명시적 해제 필요.
생성 방법 ByteBuffer.allocate() ByteBuffer.allocateDirect()
성능 낮음 높음 (대규모 I/O 작업에 최적화)
메모리 할당/해제 속도 빠름 느림 (JVM에서 관리되지 않아 비용이 많이 드는 system call을 통해야 한다)

 

예제 코드

    public static void main(String[] args) {
        ByteBuffer heapByteBuffer = ByteBuffer.allocate(1024);
        ByteBuffer directByteBuffer = ByteBuffer.allocateDirect(1024);

        log.info("heapByteBuffer isDirect: {}", heapByteBuffer.isDirect());
        log.info("directByteBuffer isDirect: {}", directByteBuffer.isDirect());

        File file = new File(Objects.requireNonNull(FIleInputStreamExample.class
                .getClassLoader()
                .getResource("file-channel.txt"))
            .getFile());

        try(FileChannel fileChannel = FileChannel.open(file.toPath())){

            fileChannel.read(heapByteBuffer);
            heapByteBuffer.flip();
            log.info("heapByteBuffer로 읽기");
            CharBuffer heapByteBufferResult = StandardCharsets.UTF_8.decode(heapByteBuffer);
            log.info("heapByteBufferResult: {}", heapByteBufferResult);

            // 포지션을 0으로 초기화 
            fileChannel.position(0);

            log.info("directByteBuffer로 읽기");
            fileChannel.read(directByteBuffer);
            directByteBuffer.flip();
            CharBuffer directByteBufferResult = StandardCharsets.UTF_8.decode(directByteBuffer);
            log.info("directByteBufferResult: {}", directByteBufferResult);

        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            heapByteBuffer.clear();
            directByteBuffer.clear();
        }
    }

 

결과

18:21:52.063 [main] INFO example.nio.buffer.ByteBufferMain -- heapByteBuffer isDirect: false
18:21:52.064 [main] INFO example.nio.buffer.ByteBufferMain -- directByteBuffer isDirect: true
18:21:52.065 [main] INFO example.nio.buffer.ByteBufferMain -- heapByteBuffer로 읽기
18:21:52.065 [main] INFO example.nio.buffer.ByteBufferMain -- heapByteBufferResult: abcdefghigjlmidfg
18:21:52.065 [main] INFO example.nio.buffer.ByteBufferMain -- directByteBuffer로 읽기
18:21:52.065 [main] INFO example.nio.buffer.ByteBufferMain -- directByteBufferResult: abcdefghigjlmidfg

'Reactive Programmming' 카테고리의 다른 글

select, epoll  (0) 2025.01.12
File Descriptor, File Table, Inode Table  (0) 2025.01.12
Reactive Programming 을 적용하는 이유?  (0) 2025.01.09
Reactive System, Stream, Programming  (0) 2025.01.01
Reactive Manifesto?  (0) 2025.01.01