Как размер буфера влияет на производительность канала NIO?

Я читал реализацию Hadoop IPC. https://github.com/apache/hadoop/blob/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/Server.java< /а>

/**
 * When the read or write buffer size is larger than this limit, i/o will be 
 * done in chunks of this size. Most RPC requests and responses would be
 * be smaller.
 */
private static int NIO_BUFFER_LIMIT = 8*1024; //should not be more than 64KB.

/**
 * This is a wrapper around {@link WritableByteChannel#write(ByteBuffer)}.
 * If the amount of data is large, it writes to channel in smaller chunks. 
 * This is to avoid jdk from creating many direct buffers as the size of 
 * buffer increases. This also minimizes extra copies in NIO layer
 * as a result of multiple write operations required to write a large 
 * buffer.  
 *
 * @see WritableByteChannel#write(ByteBuffer)
 */
private int channelWrite(WritableByteChannel channel, 
                         ByteBuffer buffer) throws IOException {

  int count =  (buffer.remaining() <= NIO_BUFFER_LIMIT) ?
               channel.write(buffer) : channelIO(null, channel, buffer);
  if (count > 0) {
    rpcMetrics.incrSentBytes(count);
  }
  return count;
}


/**
 * This is a wrapper around {@link ReadableByteChannel#read(ByteBuffer)}.
 * If the amount of data is large, it writes to channel in smaller chunks. 
 * This is to avoid jdk from creating many direct buffers as the size of 
 * ByteBuffer increases. There should not be any performance degredation.
 * 
 * @see ReadableByteChannel#read(ByteBuffer)
 */
private int channelRead(ReadableByteChannel channel, 
                        ByteBuffer buffer) throws IOException {

  int count = (buffer.remaining() <= NIO_BUFFER_LIMIT) ?
              channel.read(buffer) : channelIO(channel, null, buffer);
  if (count > 0) {
    rpcMetrics.incrReceivedBytes(count);
  }
  return count;
}

Логика такова: если буфер мал, он будет читать/записывать канал один раз. Если буфер большой, он будет делать это много раз, и каждый раз считывать/записывать 8кб.

Я не понимаю javadocs и почему это так. Почему «это сделано для того, чтобы jdk не создавал много прямых буферов по мере увеличения размера буфера»? Влияет ли большой размер буфера на скорость чтения?

Я понимаю, как размер буфера влияет на производительность FileInputStream (ссылка ). Но вот SocketChannel. Так что это не связано.


person waltersu    schedule 28.12.2015    source источник


Ответы (1)


Хороший вопрос. sun.nio.ch.IOUtil используется при записи в канал, и в его функции write(..) есть следующие строки:

int var7 = var5 <= var6?var6 - var5:0;
ByteBuffer var8 = Util.getTemporaryDirectBuffer(var7);

Вот Util.getTemporaryDirectBuffer

static ByteBuffer getTemporaryDirectBuffer(int var0) {
    Util.BufferCache var1 = (Util.BufferCache)bufferCache.get();
    ByteBuffer var2 = var1.get(var0);
    if(var2 != null) {
        return var2;
    } else {
        if(!var1.isEmpty()) {
            var2 = var1.removeFirst();
            free(var2);
        }

        return ByteBuffer.allocateDirect(var0);
    }
}

А при большой нагрузке и когда int var0 находится в большом диапазоне, это создаст много новых буферов и free(..) старых. Поскольку bufferCache имеет ограниченную длину (равна IOUtil.IOV_MAX, которая определена в конфигурации системы. On modern Linux systems, the limit is 1024) и не будет хранить буферы любой длины.
Я думаю, что это имелось в виду в This is to avoid jdk from creating many direct buffers as the size of buffer increases..

person dezhik    schedule 28.12.2015