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