DirectByteBuffer实现原理分析

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并不会提高性能

 

      

posted on 2017-11-10 17:47  kenny.wmh  阅读(2802)  评论(0编辑  收藏  举报

导航