# **ByteBuffer란?** `ByteBuffer`는 Java NIO(Non-blocking I/O)에서 **바이트 데이터를 효율적으로 다룰 수 있도록 제공하는 클래스**이다. 기존의 `InputStream` 및 `OutputStream` 기반의 **blocking I/O**와 달리, **비동기적(Non-blocking)**으로 데이터를 처리할 수 있는 구조를 제공한다. 이 클래스는 **버퍼(Buffer)**라는 개념을 사용하여 데이터를 읽고 쓸 때 **직접 메모리에서 조작**할 수 있도록 하며, 성능 최적화에 유리하다. 특히 **파일 I/O, 네트워크 전송, 바이너리 데이터 처리** 등에서 활용된다. --- ## **1. ByteBuffer의 주요 특징** ✔ **고정된 크기의 버퍼**를 사용하여 데이터를 읽고 쓴다. ✔ **Direct Buffer(직접 버퍼)와 Heap Buffer(힙 버퍼)** 두 가지 방식이 있다. ✔ **데이터를 읽고 쓰는 포인터(위치, 한계, 용량)가 존재**하여 데이터 흐름을 효율적으로 관리한다. ✔ **채널(Channel)과 함께 사용하여 고성능 I/O 처리**가 가능하다. --- ## **2. ByteBuffer의 구조** `ByteBuffer`는 데이터를 저장하는 **고정된 크기의 메모리 공간**을 가지며, 다음과 같은 **3가지 중요한 속성**을 갖는다. | 속성 | 설명 | |------|------| | **position** | 현재 읽거나 쓸 위치 (0부터 시작) | | **limit** | 읽거나 쓸 수 있는 최대 위치 | | **capacity** | 버퍼의 전체 크기 (변경 불가) | ### **🔹 주요 속성 변화 예시** ```java ByteBuffer buffer = ByteBuffer.allocate(10); System.out.println("초기 상태: " + buffer); // 출력: java.nio.HeapByteBuffer[pos=0 lim=10 cap=10] ``` 위 상태에서 데이터를 `put()`하면 `position`이 증가하고, `flip()`을 호출하면 `position`이 0으로 초기화되어 데이터를 `get()`으로 읽을 준비를 한다. --- ## **3. ByteBuffer의 주요 메서드 정리** | 메서드 | 설명 | |--------|------| | `allocate(int capacity)` | 힙 메모리에 지정한 크기의 버퍼 생성 | | `allocateDirect(int capacity)` | OS의 직접 메모리에 버퍼 생성 (성능 최적화) | | `put(byte b)` | 한 바이트 추가 | | `put(byte[] src)` | 바이트 배열을 버퍼에 추가 | | `get()` | 현재 위치의 바이트를 가져오고 `position`을 증가 | | `get(byte[] dst)` | 데이터를 바이트 배열로 가져옴 | | `flip()` | **쓰기 모드 → 읽기 모드** 변경 (`position=0`, `limit=현재 position`) | | `clear()` | 버퍼를 초기화 (`position=0`, `limit=capacity`) | | `rewind()` | **읽기 모드에서 처음부터 다시 읽기** (`position=0`, `limit` 유지) | | `compact()` | 아직 읽지 않은 데이터는 유지한 채, 새로운 데이터를 쓸 수 있도록 `position`을 조정 | | `mark()` | 현재 `position`을 저장 | | `reset()` | 저장한 `mark` 위치로 `position`을 되돌림 | --- ## **4. ByteBuffer 사용 예제** ### **(1) ByteBuffer 생성과 데이터 추가 (`put()`, `flip()`, `get()`)** ```java import java.nio.ByteBuffer; public class ByteBufferExample { public static void main(String[] args) { // 10바이트 크기의 버퍼 생성 ByteBuffer buffer = ByteBuffer.allocate(10); // 데이터 추가 (쓰기 모드) buffer.put((byte) 1); buffer.put((byte) 2); buffer.put((byte) 3); System.out.println("데이터 추가 후: " + buffer); // 읽기 모드로 변경 (flip) buffer.flip(); System.out.println("flip() 후: " + buffer); // 데이터 읽기 System.out.println("읽은 데이터: " + buffer.get()); // 1 System.out.println("읽은 데이터: " + buffer.get()); // 2 System.out.println("get() 후: " + buffer); } } ``` ✔ `flip()`을 호출하면 `position`이 0이 되어 데이터를 읽을 준비를 한다. ✔ `get()`을 호출할 때마다 `position`이 증가하여 다음 데이터를 읽을 수 있다. --- ### **(2) `compact()`와 `clear()` 차이점** ```java import java.nio.ByteBuffer; public class ByteBufferCompactClearExample { public static void main(String[] args) { ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put((byte) 10); buffer.put((byte) 20); buffer.put((byte) 30); buffer.flip(); // 읽기 모드 전환 System.out.println("flip() 후: " + buffer); System.out.println("읽은 데이터: " + buffer.get()); // 10 System.out.println("읽은 데이터: " + buffer.get()); // 20 buffer.compact(); // 읽지 않은 데이터 유지한 채 쓰기 모드 변경 System.out.println("compact() 후: " + buffer); buffer.clear(); // 완전히 초기화 System.out.println("clear() 후: " + buffer); } } ``` ✔ **`compact()`는 읽지 않은 데이터를 유지하고 `position`을 이동** ✔ **`clear()`는 전체를 초기화하고 `position=0`으로 변경** --- ### **(3) DirectBuffer 사용 (`allocateDirect()`)** ```java import java.nio.ByteBuffer; public class DirectByteBufferExample { public static void main(String[] args) { // DirectBuffer 생성 ByteBuffer directBuffer = ByteBuffer.allocateDirect(10); directBuffer.put((byte) 42); directBuffer.flip(); System.out.println("DirectBuffer 데이터: " + directBuffer.get()); // 42 } } ``` ✔ `allocateDirect()`를 사용하면 **JVM의 힙 메모리가 아닌 OS의 직접 메모리에 할당**하여 성능을 높일 수 있다. ✔ 다만, **GC(가비지 컬렉터)가 자동으로 해제하지 않기 때문에 직접 관리해야 한다.** --- ## **5. ByteBuffer vs. 일반 배열** | 비교 항목 | `ByteBuffer` | 일반 `byte[]` 배열 | |----------|-------------|----------------| | 메모리 할당 | 힙(Heap) 또는 직접 메모리(Direct) | 힙 메모리 | | 데이터 조작 | position/limit을 활용한 조작 | 단순한 인덱스 접근 | | 성능 | `allocateDirect()` 사용 시 속도 향상 | 단순 배열보다 속도가 느릴 수 있음 | | 가비지 컬렉션 | DirectBuffer는 수동 해제 필요 | 자동 관리 | ✔ **파일 I/O, 네트워크 프로그래밍에서는 `ByteBuffer`를 사용**하는 것이 효율적이다. ✔ **단순한 배열 조작이라면 `byte[]`가 더 간단하다.** --- ## **6. 결론** `ByteBuffer`는 **Java NIO에서 고성능 I/O 처리를 위한 핵심 클래스**로, 데이터를 읽고 쓰는 방식이 기존의 `InputStream`보다 **더 유연하고 효율적**이다. 특히 **파일 I/O, 네트워크 전송, 바이너리 데이터 처리**에 적합하며, **DirectBuffer**를 사용하면 성능을 극대화할 수 있다.