Java不安全与DirectByteBuffer

Java不安全与DirectByteBuffer,java,performance,io,unsafe,Java,Performance,Io,Unsafe,我正在努力有效地处理文件。为此,我首先使用MappedByteBuffer将文件映射到内存中: public static ByteBuffer getByteBuffer(String filePath, int start, long size) throws IOException { File binaryFile = new File(filePath); FileChannel binaryFileChannel = new RandomAccessFile(bina

我正在努力有效地处理文件。为此,我首先使用
MappedByteBuffer
将文件映射到内存中:

public static ByteBuffer getByteBuffer(String filePath, int start, long size) throws IOException
{
    File binaryFile = new File(filePath);
    FileChannel binaryFileChannel = new RandomAccessFile(binaryFile, "r").getChannel();

    return binaryFileChannel.map(FileChannel.MapMode.READ_ONLY, start, size);
}
然后,我调用“通常的”
getInt()
,直到处理完整个文件

为了进一步加快速度,我发现了
Unsafe
类,该类在本文中得到了很好的解释。由于它使用本机方法,因此应该比“安全”缓冲区快。我编写了以下测试代码:

import sun.misc.Unsafe;
import sun.nio.ch.DirectBuffer;

import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

public class UnsafeTesting
{
    private ByteBuffer destinationByteBuffer;
    private ByteBuffer sourceByteBuffer;

    private UnsafeTesting()
    {
        int capacity = 1_000_000_000;
        destinationByteBuffer = allocateByteBuffer(capacity);
        sourceByteBuffer = allocateByteBuffer(capacity);

        for (int byteBufferIndex = 0; byteBufferIndex < sourceByteBuffer.capacity() - 3; byteBufferIndex += 4)
        {
            sourceByteBuffer.putInt(byteBufferIndex);
        }

        destinationByteBuffer.clear();
        sourceByteBuffer.clear();
    }

    private ByteBuffer allocateByteBuffer(int capacity)
    {
        return ByteBuffer.allocateDirect(capacity).order(ByteOrder.nativeOrder());
    }

    private void runTest(boolean useUnsafeMethod) throws Exception
    {
        Unsafe unsafe = getUnsafeInstance();
        long destinationByteBufferAddress = ((DirectBuffer) destinationByteBuffer).address();
        long sourceByteBufferAddress = ((DirectBuffer) sourceByteBuffer).address();

        int executionsCount = 0;

        if (useUnsafeMethod)
        {
            for (int sourceBufferIndex = 0; sourceBufferIndex < destinationByteBuffer.remaining() - 3; sourceBufferIndex += 4)
            {
                long sourceOffset = sourceByteBufferAddress + sourceBufferIndex;
                int value = unsafe.getInt(sourceOffset);

                long targetOffset = destinationByteBufferAddress + sourceBufferIndex;
                unsafe.putInt(targetOffset, value);

                executionsCount++;
            }
        } else
        {
            while (sourceByteBuffer.remaining() > 3)
            {
                int value = destinationByteBuffer.getInt();
                sourceByteBuffer.putInt(value);

                executionsCount++;
            }
        }

        boolean equal = sourceByteBuffer.equals(destinationByteBuffer);

        if (!equal)
        {
            throw new IllegalStateException("Buffers not equal!");
        }

        System.out.println("Executions: " + executionsCount);
    }

    private static Unsafe getUnsafeInstance() throws Exception
    {
        Field unsafe = Unsafe.class.getDeclaredField("theUnsafe");
        unsafe.setAccessible(true);

        return (Unsafe) unsafe.get(null);
    }

    private static void runTest(UnsafeTesting unsafeTesting, boolean useUnsafeMethod) throws Exception
    {
        long startingTime = System.nanoTime();
        unsafeTesting.runTest(useUnsafeMethod);
        long nanoSecondsTaken = System.nanoTime() - startingTime;
        double milliSecondsTaken = nanoSecondsTaken / 1e6;
        System.out.println(milliSecondsTaken + " milliseconds taken");
    }

    public static void main(String[] arguments) throws Exception
    {
        UnsafeTesting unsafeTesting = new UnsafeTesting();

        System.out.println("### Unsafe ###");
        runTest(unsafeTesting, true);
        System.out.println();

        System.out.println("### Direct ###");
        runTest(unsafeTesting, false);
    }
}

为什么不安全的方法较慢?一个想法是,由于直接寻址,它不会按顺序处理数据。也许有一种方法可以使用
Unsafe
按顺序处理缓冲区,这样可以更快?使用
IntBuffer
大约与
ByteBuffer
一样快,因此没有多少好处。

在使用ByteBuffer方法执行复制后,将缓冲区与
sourceByteBuffer.equals(destinationByteBuffer)
进行比较时,实际上没有做任何工作:两个缓冲区的位置都在缓冲区的末尾。这就是大部分时间都花在“不安全”案例中的地方。要使它真正比较事物,您应该在比较两个缓冲区之前将它们定位(0)。事实上,您可能不应该将其包括在计时中,然后您会发现不安全的速度更快。在我的机器上,不安全的情况大约为200毫秒,字节缓冲区情况大约为600毫秒(使用您的代码测量)。@starikoff:谢谢您的
equals()
更正。为什么
Unsafe
的性能变化如此之大?这似乎很不一致。现在对我来说也更快了,但不总是。。。
### Unsafe ###
Executions: 250000000
1687.07085 milliseconds taken

### Direct ###
Executions: 250000000
657.23575 milliseconds taken