Почему разница в кривой производительности между ByteBuffer. allocate () и B yteBuffer.allocateDirect ()

Я работаю над некоторым кодом SocketChannel -to- SocketChannel , который лучше всего работает с прямым байтовым буфером - долгоживущим и большим (от десятков до сотен мегабайт на соединение.) При хешировании точной структуры цикла с помощью FileChannel s, я провел несколько микро-тестов на ByteBuffer.allocate () vs. ByteBuffer.allocateDirect () производительность.

Был сюрприз в результатах, который я не могу объяснить. На приведенном ниже графике есть очень явный провал в 256 КБ и 512 КБ для реализации передачи ByteBuffer.allocate () - производительность падает примерно на 50%! Также кажется, что для ByteBuffer.allocateDirect () падение производительности должно быть меньше. (Серия% -gain помогает визуализировать эти изменения.)

Размер буфера (байты) в зависимости от времени (MS)

The Pony Gap

Почему разница кривой производительности между ByteBuffer.allocate () и ] ByteBuffer.allocateDirect () ? Что именно происходит за кулисами?

Это очень хорошо, возможно, зависит от оборудования и ОС, так что вот эти подробности:

  • MacBook Pro с двухъядерным процессором Core 2 CPU
  • SSD-накопитель Intel X25M
  • OSX 10.6.4

Исходный код, по запросу:

package ch.dietpizza.bench;

import static java.lang.String.format;
import static java.lang.System.out;
import static java.nio.ByteBuffer.*;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;

public class SocketChannelByteBufferExample {
    private static WritableByteChannel target;
    private static ReadableByteChannel source;
    private static ByteBuffer          buffer;

    public static void main(String[] args) throws IOException, InterruptedException {
        long timeDirect;
        long normal;
        out.println("start");

        for (int i = 512; i <= 1024 * 1024 * 64; i *= 2) {
            buffer = allocateDirect(i);
            timeDirect = copyShortest();

            buffer = allocate(i);
            normal = copyShortest();

            out.println(format("%d, %d, %d", i, normal, timeDirect));
        }

        out.println("stop");
    }

    private static long copyShortest() throws IOException, InterruptedException {
        int result = 0;
        for (int i = 0; i < 100; i++) {
            int single = copyOnce();
            result = (i == 0) ? single : Math.min(result, single);
        }
        return result;
    }


    private static int copyOnce() throws IOException, InterruptedException {
        initialize();

        long start = System.currentTimeMillis();

        while (source.read(buffer)!= -1) {    
            buffer.flip();  
            target.write(buffer);
            buffer.clear();  //pos = 0, limit = capacity
        }

        long time = System.currentTimeMillis() - start;

        rest();

        return (int)time;
    }   


    private static void initialize() throws UnknownHostException, IOException {
        InputStream  is = new FileInputStream(new File("/Users/stu/temp/robyn.in"));//315 MB file
        OutputStream os = new FileOutputStream(new File("/dev/null"));

        target = Channels.newChannel(os);
        source = Channels.newChannel(is);
    }

    private static void rest() throws InterruptedException {
        System.gc();
        Thread.sleep(200);      
    }
}
31
задан Stu Thompson 6 September 2010 в 15:34
поделиться