네트워크 통신 등의 버퍼를 사용하는 작업에는 ByteBuffer 클래스를 많이 사용한다.
byte 배열을 사용하는 경우 잦은 GC(garbage collection) 가 성능에 영향을 줄 수 있다.
목차
1)ByteBuffer instance 생성: allocate, allocateDirect
2)ByteBuffer 초기화: clear
3)ByteBuffer 사용 가능 크기 변경: limit
4)ByteBuffer 쓰기: put*
5)ByteBuffer 읽기: get*
6)ByteBuffer 읽기/쓰기 작업 병행시: flip
7)ByteBuffer 에 남은 데이터 처리: compact
1)ByteBuffer instance 생성: allocate, allocateDirect
ByteBuffer 클래스에는 allocate 함수와 allocateDirect 함수가 있다.
두 함수 모두 static 이고 int 값을 파라미터로 전달받으며 버퍼의 크기를 지정한다.
예)
ByteBuffer buffer = ByteBuffer.allocate(1024);allocateDirect 함수의 경우 사용하는 플랫폼(안드로이드 등의 모바일 플랫폼) 에 따라 정상적으로 동작하지 않는 경우도 있으므로 반드시 플랫폼이 지원을 하는지 테스트해 보고 사용하길 권한다.
2)ByteBuffer 초기화: clear
clear 함수는 해당 ByteBuffer instance 가 생성되었을 때 상태로 만들어 준다.
3)ByteBuffer 사용 가능 크기 변경: limit
limit(int newLimit) 함수를 사용하여 쓰기 가능 영역 크기를 조정할 수 있다.
파라미터로 넘기는 값이 allocate 로 지정한 capacity 를 초과할 수 없다.
예)
ByteBuffer buffer = ByteBuffer.allocate(1024); buffer.limit(); // 1024 를 리턴 buffer.limit(50); //buffer.limit(2048); // 허용되지 않음 buffer.limit(); // 50 를 리턴
4)ByteBuffer 쓰기: put*
put* 함수들을 이용해서 데이터를 ByteBuffer 에 넣어준다.
예)
ByteBuffer buffer = ByteBuffer.allocate(1024); buffer.put((byte)0x01); buffer.put(new byte[] {0x02, 0x03}); buffer.put((byte)0x04);결과:
buffer.array() => [0x01, 0x02, 0x03, 0x0x04, ...]
5)ByteBuffer 읽기: get*
get* 함수들을 이용해서 원하는 데이터 크기만큼 데이터를 읽을 수 있다.
get* 함수를 이용해서 데이터를 읽으면 다음 get* 함수 이용시 이전 get* 함수를 이용해 읽은 다음 부분부터 값을 읽는다.
예)
ByteBuffer buffer = ByteBuffer.wrap(new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}); byte a = buffer.get(); byte b = buffer.get(); byte[] c = new byte[2]; buffer.get(c); byte d = buffer.get();
결과:
a => 0x01
b => 0x02
c => [0x03, 0x04]
d => 0x05
6)ByteBuffer 읽기/쓰기 작업 병행시: flip
put* 함수를 이용해서 값을 쓰거나 SocketChannel 의 read 함수로 ByteBuffer instance 에 값을 쓰고 나서 데이터를 읽기 전에 ByteBuffer 클래스의 flip 함수를 한번 호출해야 한다.
예) http://download.oracle.com/javase/6/docs/api/java/nio/Buffer.html#flip()
buf.put(magic); // Prepend header in.read(buf); // Read data into rest of buffer buf.flip(); // Flip buffer out.write(buf); // Write header + data to channel
buf.put(magic) 과 in.read(buf) 모두 buf 에 데이터를 쓴다.
데이터를 쓰고 나서 buf.flip() 으로 모드 변환을 해주고
out.write(buf) 로 buf 의 내용을 읽는다.
7)ByteBuffer 에 남은 데이터 처리: compact
socket 통신의 경우 buffer 에 읽을 수 있는 양이 찰 때까지 read 함수로 buffer 를 채우고 buffer 가 충분히 차면 의미있는 범위까지 데이터를 읽고 buffer 의 남은 부분을 유지하고 남은 부분 다음부터 데이터를 채우는 작업을 반복하는 경우가 있다.
이때 데이터의 남은 부분을 buffer 의 앞으로 이동시키고 남은 부분 다음부터 쓸 수 있게 하는 함수가 compact 함수이다.
예)
ByteBuffer buffer = ByteBuffer.allocate(1024); byte[] data = new byte[16]; buffer.clear(); // ByteBuffer 초기화 int len = 0; while ((len = in.read(buffer)) > 0) { // ByteBuffer 쓰기 buffer.flip(); // 쓰기 작업이 끝나고 읽기 작업을 위해 flip while (buffer.remaining() > 16) { // remaining 함수는 읽을 수 있는 크기를 리턴 buffer.get(data); // 16 바이트만큼 데이터를 읽음 // data 처리 } buffer.compact(); // 남은 부분을 ByteBuffer 맨 앞으로 이동 // 다음 read 작업에서 남은 부분 다음부터 채움 }
댓글 없음:
댓글 쓰기