버퍼는 운영체제의 커널이 관리하는 시스템 메모리를 직접 사용 할 수있다.
byte[]인 경우 jvm의 힙영역에 메모리가 할당되고 바이트 배열의 초기값이 시스템 메모리로 한번 복사 되어야한다.
이렇게 복사 뿐만아니라 운영체제 수준에서 제공해주는 dma, 가상 메모리, 메모리 맵 파일들의 기능을 사용할 수 없다.
position - 현재 위치
limit - 버퍼에서 실제로 어디까지 사용할지를 지정
capacity - 메모리 크기, 몇개를 넣을 수 있는가. intbuffer의 capacity 100이면 int형 100개, 초기값 -1
mark - reset() 시 돌아갈 현재 position 설정
* Buffer 클래스
public abstract class Buffer{
//위치값 리턴
public final int position();
public final int limit();
public final int capacity();
//위치값 설정
public final Buffer position(int newPosition);
public final Buffer limit(int newLimit);
public final Buffer mark(); //mark 할 현재 position 지정
public final Buffer reset();//mark 위치로
public final int remaining() ; // (limit - position) 현재position에서 limit까지 읽을 수있는 개수
public final boolean hasRemaining(); //읽을 것이 있는지
public abstract boolean isReadOnly(); //읽기 전용인지(추상)
}
*Buffer 의 메소드들
- clear() : 모든 속성값 초기화, 데이터는 변화 없음, mark 값 -1 초기화
- rewind() : position 속성 초기화, mark 값 -1, 읽었던 데이터를 다시 읽을때 사용
- flip() : limit을 position이 있던 위치로 설정 후 position을 0으로 이동, mark = -1
버퍼를 재사용하기위해 clear()하고 데이터를 버퍼에 쓴후 flip()으로 재사용 범위를 지정한 후 버퍼에서 데이터를 읽음
- compact() : position에서 limit 사이이, 남아있는 데이터를 버퍼의 맨 앞에부터 순서대로 쓴다.
쓴 위치만큼 position을 이동하고 limit는 버퍼가 생성되는 시점, capacity와 동일하게 된다 mark = -1
: 버퍼 안의 데이터를 남기없이 모두 전송하고 싶을 때
buf.clear(); //만약, 읽을 데이터가 있다면 채널에서 버퍼로 데이터를 읽어들인다. while(in.read(buf)>0 && buf.hasRemaining()){ buf.flip(); out.write(buf); //전송하지 못한 데이터가 있다면 버퍼의 맨 앞부분으로 모두 복사해서 다음 번에 전송되게 한다 buf.compact(); } |
- duplicate() : 복사본 생성(속성까지)
각 속성은 다를 수 있지만, 데이터는 같은 메모리 공간을 참조하기때문에 변경시 같이 변경
- slice() : 버퍼의 일부분만 복사, 복사된 것의 속성은 초기화, 데이터는 공유됨
*ByteBuffer 클래스
public abstact class ByteBuffer extends Buffer implements Comparable{
//팩토리 메소드를 사용해서 만드는 방법
public static ByteBuffer allocate(int capcity);
//이미 존재하는 배열을 이용해서 만드는 방법
public static ByteBuffer wrap(byte[] array);
public static ByteBuffer wrap(byte[] array, int offset, int length);
//유틸리티 메소드들
public final boolean hasArray();
public final byte[] array();
public final int arrayOffset();
}
- 상대적, 절대적 읽기 쓰기
- 상대적 : get(),put() 후 position 변경
- 절대적 : position이 변경되지 않음
- 배열을 이용하여 한번에 값을 읽고 쓰기 할때
: 사용 가능한 길이를 먼저 계산후 사용
byte[] b = new byte[3]; // 버퍼에서 얼마나 쓸 수 있는지를 계산.. int size = buf.remaining(); if (b.length < size) { size = b.length; } buf.get(b, 0, size); buf.put(b, 0, size); |
- 생성
: ByteBuffer buf = ByteBuffer.allocate(1000);
: byte[] arr = new byte[1024];
ByteBuffer buf = ByteBuffer.wrap(arr);
* allcocate(), wrap() 생성된 버퍼는 jvm 힙 영역에 저장되는 넌다이렉트 버퍼이다
넌다이렌트 버퍼에는 내부적으로 보조 배열이 있다.
hasArray()메소드로 true가 리턴됨을 알수 있다.
* 시스템 메모리를 사용할 수있는 다이렉트 버퍼는 ByteBuffer만 생성할 수 있다.
자바에서 사용하는 바이트 배열은 시스템 메모리에서 사용하는 순차적인 바이트들의 집함이 아닌
객체 내에 바이트들을 저장하고 있는 형태기 때문에 커널이 관리하는 시스템 메모리에 직접 저장할 수 있는 형태가 아님
* 다이렉트 버퍼 생성
ByteBuffer directBuffer = ByteBuffer.allocateDirect(1024); boolean isDirect = directBuffer.isDirect(); |
- 채널과 네이티브 IO 루틴들을 이용가능
- 메소드 파라미터로 주어진 크기만큼의 시스템 메모리를 jni를 사용해서 할당
- 이 시스템 메모리를 래핑하는 자바 객체를 만들어 리턴
* 다이렉트 버퍼를 메모리에 로드하거나 릴리즈하는 것은 넌다이렉트 버퍼를 생성,제거하는 것에 비해 부하가 크다
그러므로 다이렉트 버퍼는 일반적으로 성능에 민감하고 버퍼를 오랫동안 유지해서 사용할 필요가 있는 곳에서 사용
그 외는 넌다이렉트 버퍼를 사용
* 넌다이렉트 버퍼를 채널의 타켓으로 설정 가능하지만 좋지않다
* byteBuffer는 다양한 형식으로 읽고 쓸수 있다.(int, long....)
- position은 형식의 크기만큼 이동
* 바이트 순서: 자바는 빅인디언
ByteBuffer buf = ByteBuffer.allocate(10); System.out.println(buf.order()); buf.order(ByteOrder.LITTLE_ENDIAN); System.out.println(buf.order()); |
* charBuffer 클래스 사용
- char 2바이트
- 스트링 제어하기
public class CharBufferViewTest { public static void main(String[] args) { ByteBuffer buf = ByteBuffer.allocate(100); //뷰 버퍼 생성 CharBuffer cbuf = buf.asCharBuffer(); cbuf.put("Hello World!"); cbuf.flip(); //toString 메소드로 버퍼 안의 데이터를 스트링으로 만든다. //toString 메소드는 포지션에 영향을 주지 않는다 String s = cbuf.toString(); System.out.println("Data:"+s); System.out.println("buffer position:"+cbuf.position()); int start = 6; int end = 12; //버퍼안의 데이터 일부만을 charSequence로 가져온다 CharSequence sub = cbuf.subSequence(start, end); System.out.println(sub.toString()); } } |
'코딩 내공 Project > IO&NIO 네트워크' 카테고리의 다른 글
[NIO] 셀렉터 부분 정리 (0) | 2011.05.08 |
---|---|
[NIO] Chanel 부분 정리 (0) | 2011.05.07 |
생성자 - 소비자 (0) | 2011.03.16 |
[참고] ByteBufferPool과 ThreadPool을 추가해 성능 업그레이드하기 (0) | 2011.03.16 |
[링크] NIO API 1부 - 버퍼와 채널 (0) | 2011.03.07 |