日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android坑点-ByteBuffer.array() 入过坑吗

發(fā)布時(shí)間:2025/3/12 Android 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android坑点-ByteBuffer.array() 入过坑吗 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目錄

  • 1、坑點(diǎn)介紹
  • 2、正確使用姿勢(入坑了怎么辦)
  • 3、坑坑詳解
    • 3.1HeapByteBuffer可以用buffer.array()
    • 3.2DirectByteBuffer的坑在哪里

1、坑點(diǎn)介紹

如下代碼:

ByteBuffer buffer = ByteBuffer.allocateDirect(int capacity) byte[] array = buffer.array()

在android平臺前面會(huì)有幾個(gè)字節(jié)是沒有實(shí)際數(shù)據(jù)的,在jre環(huán)境下,發(fā)生異常。
怎么理解呢?
來個(gè)栗子:

private void bufferTest() {ByteBuffer buffer = ByteBuffer.allocateDirect(10);buffer.put((byte) 1);buffer.put((byte) 2);byte[] arr = buffer.array();//這里使用array返回字節(jié)數(shù)組for (int i = 0; i < 10; i++) {Log.d("BufferTester", "bufferTest arr[" + i + "]=" + arr[i]);}}

結(jié)果如下:

2021-10-27 15:29:43.169 D/BufferTester: bufferTest arr[0]=0
2021-10-27 15:29:43.169 D/BufferTester: bufferTest arr[1]=0
2021-10-27 15:29:43.169 D/BufferTester: bufferTest arr[2]=0
2021-10-27 15:29:43.169 D/BufferTester: bufferTest arr[3]=0
2021-10-27 15:29:43.169 D/BufferTester: bufferTest arr[4]=1
2021-10-27 15:29:43.169 D/BufferTester: bufferTest arr[5]=2
2021-10-27 15:29:43.169 D/BufferTester: bufferTest arr[6]=0
2021-10-27 15:29:43.169 D/BufferTester: bufferTest arr[7]=0
2021-10-27 15:29:43.169 D/BufferTester: bufferTest arr[8]=0
2021-10-27 15:29:43.169 D/BufferTester: bufferTest arr[9]=0

通過上面的結(jié)果可以看到 arr[4]=1, arr[5]=2。我們是put了1和2,正常情況是從數(shù)組第一個(gè)元素開始寫入,我們?nèi)〕龅臄?shù)組卻跳躍了前面4個(gè)字節(jié)。

2、正確使用姿勢(入坑了怎么辦)

實(shí)際上buffer.array() 是不能用的,我們需要使用get(byte[] dst) 或get(byte[] dst, int offset, int length),具體代碼如下

private void bufferTest() {ByteBuffer buffer = ByteBuffer.allocateDirect(10);buffer.put((byte) 1);buffer.put((byte) 2); // byte[] arr = buffer.array();buffer.position(0);byte []arr = new byte[10];//put 2次,實(shí)際是2個(gè)字節(jié)buffer.get(arr);for (int i = 0; i < 10; i++) {Log.d("BufferTester", "bufferTest arr[" + i + "]=" + arr[i]);}}

結(jié)果:

2021-10-27 15:53:49.954 D/BufferTester: bufferTest arr[0]=1
2021-10-27 15:53:49.954 D/BufferTester: bufferTest arr[1]=2
2021-10-27 15:53:49.954 D/BufferTester: bufferTest arr[2]=0
2021-10-27 15:53:49.954 D/BufferTester: bufferTest arr[3]=0
2021-10-27 15:53:49.954 D/BufferTester: bufferTest arr[4]=0
2021-10-27 15:53:49.954 D/BufferTester: bufferTest arr[5]=0
2021-10-27 15:53:49.954 D/BufferTester: bufferTest arr[6]=0
2021-10-27 15:53:49.954 D/BufferTester: bufferTest arr[7]=0
2021-10-27 15:53:49.954 D/BufferTester: bufferTest arr[8]=0
2021-10-27 15:53:49.954 D/BufferTester: bufferTest arr[9]=0

arr[0]=1,arr[1]=2 是我們期望的結(jié)果,也是正確結(jié)果。
注:put一字節(jié),postion+1,所以上述代碼在取的時(shí)候,將pos恢復(fù)到起始位置。
所以請使用get方法來獲取內(nèi)容。

如果還是要用array(),那么一定要完全掌握好DirectByteBuffer的機(jī)制。

3、坑坑詳解

ByteBuffer是一個(gè)抽象類,通過類函數(shù) allocateDirect(int capacity)創(chuàng)建的是DirectByteBuffer對象;通過類函數(shù)allocate(int capacity)創(chuàng)建的是HeapByteBuffer對象。關(guān)系和代碼如下

  • HeapByteBuffer extends ByteBuffer
  • public static ByteBuffer allocate(int capacity) {if (capacity < 0)throw new IllegalArgumentException();return new HeapByteBuffer(capacity, capacity);}
  • DirectByteBuffer extends MappedByteBuffer extends ByteBuffer
  • public static ByteBuffer allocateDirect(int capacity) {if (capacity < 0) {throw new IllegalArgumentException("capacity < 0: " + capacity);}DirectByteBuffer.MemoryRef memoryRef = new DirectByteBuffer.MemoryRef(capacity);return new DirectByteBuffer(capacity, memoryRef);}

    簡單過一下:HeapByteBuffer 是堆上分配的空間,DirectByteBuffer是系統(tǒng)分配的空間。

    3.1HeapByteBuffer可以用buffer.array()

    private HeapByteBuffer(int cap, int lim, boolean isReadOnly) {super(-1, 0, lim, cap, new byte[cap], 0);this.isReadOnly = isReadOnly;}

    因?yàn)檎{(diào)用super的時(shí)候,就 按照給定的大小(new byte[cap]) 分配了數(shù)組傳遞給父類,最終調(diào)用array()的時(shí)候,就返回的這個(gè)數(shù)組。

    3.2DirectByteBuffer的坑在哪里

    注意了,我們重點(diǎn)看兩個(gè)構(gòu)造函數(shù)
    DirectByteBuffer.MemoryRef memoryRef = new DirectByteBuffer.MemoryRef(capacity);
    return new DirectByteBuffer(capacity, memoryRef);

  • MemoryRef內(nèi)存分配
    注意看注釋要點(diǎn)1、2、3:
  • MemoryRef(int capacity) {VMRuntime runtime = VMRuntime.getRuntime();//要點(diǎn)1,分配了一個(gè)字節(jié)數(shù)組,大小是我們給的大小+ 7,例如我們給10,分配了17字節(jié)buffer = (byte[]) runtime.newNonMovableArray(byte.class, capacity + 7);//要點(diǎn)2,得到buffer的地址(指針)allocatedAddress = runtime.addressOf(buffer);// Offset is set to handle the alignment: http://b/16449607//要點(diǎn)3、計(jì)算一個(gè)偏移量,計(jì)算結(jié)果是在0-7之間。offset = (int) (((allocatedAddress + 7) & ~(long) 7) - allocatedAddress);isAccessible = true;isFreed = false;originalBufferObject = null;}
  • DirectByteBuffer(int capacity, MemoryRef memoryRef)內(nèi)存管理與使用
  • DirectByteBuffer(int capacity, MemoryRef memoryRef) {//要點(diǎn)4、將要點(diǎn)1的數(shù)組和要點(diǎn)3的偏移傳遞給父類super(-1, 0, capacity, capacity, memoryRef.buffer, memoryRef.offset);this.memoryRef = memoryRef;//要點(diǎn)5、給address賦值為要點(diǎn)2的地址+要點(diǎn)3的偏移地址this.address = memoryRef.allocatedAddress + memoryRef.offset;cleaner = null;this.isReadOnly = false; }

    也許老鐵已經(jīng)看出了端倪,此處傳遞給父類的數(shù)組是capacity + 7長度的,其中address是數(shù)組的一個(gè)子集,舉個(gè)例子,如果capacity = 10,offset = 5,那么buffer的長度是17,allocatedAddress 是buffer[0]的地址,address 就是buffer[5] 地址。

  • put是自行實(shí)現(xiàn)的
  • public final ByteBuffer put(byte x) {if (!memoryRef.isAccessible) {throw new IllegalStateException("buffer is inaccessible");}if (isReadOnly) {throw new ReadOnlyBufferException();}put(ix(nextPutIndex()), x);return this;}private ByteBuffer put(long a, byte x) { //填充數(shù)據(jù)Memory.pokeByte(a, x);return this;}private long ix(int i) { //這里是重點(diǎn),新加入的字節(jié),用address+已經(jīng)存在的長度所在的位置進(jìn)行填充數(shù)據(jù)。return address + i;}
  • get(byte[] dst, int dstOffset, int length) 也是通過addr來操作的
  • public ByteBuffer get(byte[] dst, int dstOffset, int length) {if (!memoryRef.isAccessible) {throw new IllegalStateException("buffer is inaccessible");}checkBounds(dstOffset, length, dst.length);int pos = position();int lim = limit();assert (pos <= lim);int rem = (pos <= lim ? lim - pos : 0);if (length > rem)throw new BufferUnderflowException();//通過address來取數(shù)據(jù)Memory.peekByteArray(ix(pos),dst, dstOffset, length);position = pos + length;return this;}

    總體來說DirectByteBuffer分配了一個(gè)字節(jié)數(shù)組buffer 長度capacity+7,并計(jì)算出了一個(gè)小于7的偏移值x,再得到一個(gè)buffer的偏移地址,address = buffer+x。put、get都是通過address來存取的,因偏移,存取起始位置不一定是buffer[0],array() 返回的是buffer,因此可能存在前面x個(gè)字節(jié)沒有值。

  • buffer長度驗(yàn)證
  • private void bufferTest() {ByteBuffer buffer = ByteBuffer.allocateDirect(10);byte[] arr = buffer.array();Log.d("BufferTester", "bufferTest len = " + arr.length);

    參數(shù)給的10,buffer實(shí)際長度17:

    2021-10-27 17:18:14.740 D/BufferTester: bufferTest len = 17

    同時(shí)在jre的環(huán)境下,DirectByteBuffer的實(shí)現(xiàn)稍有區(qū)別,沒有偏移,且array被調(diào)用會(huì)拋出異常。沒有計(jì)算offset也沒有持有數(shù)組對象,只通過一個(gè)地址進(jìn)行存取。

    創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

    總結(jié)

    以上是生活随笔為你收集整理的Android坑点-ByteBuffer.array() 入过坑吗的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。