Warum die ungeraden Leistungskurvenunterschiede zwischen ByteBuffer.allocate () und ByteBuffer.allocateDirect ()

Ich arbeite an einigenSocketChannel-zuSocketChannel Code, der am besten mit einem direkten Byte-Puffer funktioniert - langlebig und groß (Zehn bis Hunderte von Megabyte pro VerbindungFileChannels, ich habe einige Micro-Benchmarks auf @ ausgefühByteBuffer.allocate() vs.ByteBuffer.allocateDirect() performance.

Es gab eine Überraschung in den Ergebnissen, die ich nicht wirklich erklären kann. In der folgenden Grafik gibt es eine sehr ausgeprägte Klippe bei den 256 KB und 512 KB für dieByteBuffer.allocate() transfer-Implementierung - die Leistung sinkt um ~ 50%! Es scheint auch eine kleinere Performance-Klippe für das @ zu gebeByteBuffer.allocateDirect(). (Die% -gain-Reihe hilft, diese Änderungen zu visualisieren.)

Buffer Size (Bytes) gegen Time (MS)

Warum die ungerade Leistungskurvendifferenz zwischenByteBuffer.allocate() undByteBuffer.allocateDirect()? Was genau ist hinter dem Vorhang los?

Es hängt sehr gut von der Hardware und dem Betriebssystem ab, also hier die Details:

MacBook Pro mit Dual-Core Core 2-CPUIntel X25M SSD-LaufwerkOSX 10.6.4

Quellcode, auf Anfrage:

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);      
    }
}

Antworten auf die Frage(8)

Ihre Antwort auf die Frage