1.創建DirectByteBuffer
Direct ByteBuffer是通過JNI在Java虛擬機外的內存中分配了一塊(所以即使在運行時通過-Xmx指定了Java虛擬機的最大堆內存,還是可能實例化超出該大小的Direct ByteBuffer),該內存塊並不直接由Java虛擬機負責垃圾收集.
使用allocateDirect()靜態方法創建對象分配內存
ByteBuffer buffer=ByteBuffer.allocateDirect(256);
1 /** 2 * Allocates a new direct byte buffer. 3 * 4 * <p> The new buffer's position will be zero, its limit will be its 5 * capacity, its mark will be undefined, and each of its elements will be 6 * initialized to zero. Whether or not it has a 7 * {@link #hasArray </code>backing array<code>} is unspecified. 8 * 9 * @param capacity The new buffer's capacity, in bytes 10 * @return The new byte buffer 11 * @throws IllegalArgumentException If the <tt>capacity</tt> is a negative integer 12 */ 13 public static ByteBuffer allocateDirect(int capacity) { 14 if (capacity < 0) { 15 throw new IllegalArgumentException("capacity < 0: " + capacity); 16 } 17 18 DirectByteBuffer.MemoryRef memoryRef = new DirectByteBuffer.MemoryRef(capacity); 19 return new DirectByteBuffer(capacity, memoryRef); 20 } 21 // 22 public MemoryRef(int capacity) { 23 VMRuntime runtime = VMRuntime.getRuntime(); 24 buffer = (byte[]) runtime.newNonMovableArray(byte.class, capacity + 7); 25 allocatedAddress = runtime.addressOf(buffer); 26 // Offset is set to handle the alignment: http://b/16449607 27 offset = (int) (((allocatedAddress + 7) & ~(long) 7) - allocatedAddress); 28 isAccessible = true; 29 isFreed = false; 30 }
以上方法將創建一個容量為256字節的DirectByteBuffer,如果發現創建的緩沖區容量太小,唯一的選擇就是重新創建一個大小合適的緩沖區.
DirectByteBuffer主要應用在android數據傳遞過程.減少數據與JNI數據拷貝轉換操作
DirectByteBuffer.putInt(value);
下面分析一下當執行putInt后,DirectByteBuffer都執行了什么操作
1 //計算寫數據的位置 2 @Override 3 public final ByteBuffer putInt(int x) { 4 if (!memoryRef.isAccessible) { 5 throw new IllegalStateException("buffer is inaccessible"); 6 } 7 if (isReadOnly) { 8 throw new ReadOnlyBufferException(); 9 } 10 putInt(ix(nextPutIndex(SizeOf.INT)), x); 11 return this; 12 } 13 //調用Memory來完成Int數據存儲 14 private ByteBuffer putInt(long a, int x) { 15 Memory.pokeInt(a, x, !nativeByteOrder); 16 return this; 17 } 18 19 private long ix(int i) { 20 return address + i; 21 } 22
再往下看Memory做了什么
1 public static void pokeInt(long address, int value, boolean swap) { 2 if (swap) { 3 value = Integer.reverseBytes(value); 4 } 5 pokeIntNative(address, value); 6 } 7 //因為最后執行到JNI層.這塊就不涉及到字節序的問題 8 private static native void pokeIntNative(long address, int value);
當執行 DirectByteBuffer.getInt();都執行了哪些操作
1 public int getInt() { 2 if (!memoryRef.isAccessible) { 3 throw new IllegalStateException("buffer is inaccessible"); 4 } 5 return getInt(ix(nextGetIndex(SizeOf.INT))); 6 } 7 8 //最后執行Memory 的JNI方法 9 private int getInt(long a) { 10 return Memory.peekInt(a, !nativeByteOrder); 11 } 12 //Memory 執行的操作 13 public static int peekInt(long address, boolean swap) { 14 int result = peekIntNative(address); 15 if (swap) { 16 result = Integer.reverseBytes(result); 17 } 18 return result; 19 } 20 private static native int peekIntNative(long address);
所以得出結論就本身在Java中引入DirectByteBuffer並不會提高性能