ByteBuf

이번엔 netty의 버퍼를 알아볼 차례다.
네티의 버퍼는 flip 메서드를 호출하지 않아도 읽기도 쓰기 인덱스가 분리되어 사용 가능하다.
소스를 보자.

  private void testBuffer(ByteBuf buf, boolean isDirect){
    assertEquals(11, buf.capacity());

    assertEquals(isDirect, buf.isDirect());

    buf.writeInt(65537);
    assertEquals(4, buf.readableBytes());
    assertEquals(7, buf.writableBytes());

    assertEquals(1, buf.readShort());
    assertEquals(2, buf.readableBytes());
    assertEquals(7, buf.writableBytes());

    assertEquals(true, buf.isReadable());
    buf.clear();

    assertEquals(0, buf.readableBytes());
    assertEquals(11,buf.writableBytes());
  }

  @Test
  public void createUnpooledHeapBufferTest(){
    ByteBuf byteBuf = Unpooled.buffer(11);
    testBuffer(byteBuf,false);
  }

테스트로 netty의 ByteBuf 11개를 생성하였다.
첫번째는 capacity가 11인지 확인하였다. 그리고 direct인지 확인한다.
다음으로는 65537이라는 int형 정수를 썼다.
그리고나서 읽은 바이트수를 확인한다 4바이트가 맞다. 쓸 수 있는 바이트수는 7바이트가 남았다.
65537을 16진수로 표현하면 0x10001이고 이값에 4바이트 패딩을 하면 0x00010001이 된다. 2바이트를 읽으면 1이 된다.
2바이트를 읽었으니 읽을 수 있는 바이트수는 2바이트이다. 쓸 수 있는 바이트는 아직 7바이트다.
버퍼에 데이터가 있는지 확인한다.
clear를 하면 읽을수 있는 버퍼는 없고 남은 바이트는 11이 되었다.

네티 버퍼의 장점은 동적으로 변하는 버퍼다. 소스를 보자 우리개발자니까 백마디 말보다 하나의 소스만 보면된다.

  private void testBuffer1(ByteBuf buf, boolean isDirect) {
    assertEquals(11, buf.capacity());
    assertEquals(isDirect, buf.isDirect());

    String sourceData = "hello world";
    buf.writeBytes(sourceData.getBytes());
    assertEquals(11, buf.readableBytes());
    assertEquals(0, buf.writableBytes());

    assertEquals(sourceData, buf.toString(Charset.defaultCharset()));

    buf.capacity(6);
    assertEquals("hello ", buf.toString(Charset.defaultCharset()));
    assertEquals(6, buf.capacity());

    buf.capacity(13);
    assertEquals("hello ", buf.toString(Charset.defaultCharset()));

    buf.writeBytes("world".getBytes());
    assertEquals(sourceData, buf.toString(Charset.defaultCharset()));

    assertEquals(13, buf.capacity());
    assertEquals(2, buf.writableBytes());
  }

일단 퍼버에 hello world 라고 썼다.
그러면 읽을 수 있는 버퍼의 수는 11개이고 쓸수 있는 버퍼의 수는 없다.
capacity 사이즈를 6으로 바꾸었다. 그럼 ‘hello ‘ 사이즈가 6개로 바뀌었다.
그리고 나서 사이즈를 13으로 바꿔보면 ‘hello ‘는 아직 여전히 남아있다. 저장된 데이터가 보존 되어 있다.
‘world’를 쓰면 기존의 ‘hello world’와 똑같이 남아 있고 쓸 수 있는 버퍼는 2개의 사이즈가 남아있다.
이것으로 얼추 네티의 버퍼를 알아봤다.

네티의 버퍼 생성

네티는 버퍼의 특징은 바이트 버퍼풀을 제공한다는 것이다. 이를 통해 생성된 바이트 버퍼를 재사용 할 수 있다. 바이트 버퍼 생성 방법을 알아보자

PooledByteBufAllocator.DEFAULT.heapBuffer()
PooledByteBufAllocator.DEFAULT.directBuffer()

풀링을 할 수 있는 버퍼를 생성하는 방법이다. 위 에는 힙 버퍼이고 아래는 다이렉트 버퍼이다.

Unpooled.buffer();
Unpooled.directBuffer();

풀링을 하지 않는 버퍼이다. 위 에는 힙 버퍼 이고 아래는 다이렉트 버퍼이다.

바이트 버퍼 풀을 사용함으로써 가장 큰 장점은 버퍼를 빈번히 할당하고 해제 할 때 일어나는 가비지 컬렉션 횟수의 감소이다.
이것으로 네티의 버퍼에 대해서 알아봤다.

다음에는 서드파티(Spring) 연동하는 작업을 해보자!