为啥 DirectByteBuffer.array() 有额外的大小?

Posted

技术标签:

【中文标题】为啥 DirectByteBuffer.array() 有额外的大小?【英文标题】:Why does DirectByteBuffer.array() have extra size?为什么 DirectByteBuffer.array() 有额外的大小? 【发布时间】:2018-05-29 06:54:35 【问题描述】:

我的代码是:

if (frameRGBABuffer == null) 
    frameRGBABuffer = ByteBuffer.allocateDirect(cameraHeight * cameraWidth * 4)
        .order(ByteOrder.nativeOrder());


Log.d("tag",frameRGBABuffer.array().length)

我的相机分辨率是 1280×720,因此frameRGBABuffer 应该分配 3686400 字节的空间。

但奇怪的是frameRGBABuffer.array()的长度是3686407,为什么多了7个字节的空格?

顺便说一句,frameRGBABuffer.array() 不抛出异常,返回一个带数据的 byte[]

Android 似乎分配了 7 个额外的空间来处理对齐。 源代码是:

MemoryRef(int capacity) 
    VMRuntime runtime = VMRuntime.getRuntime();
    buffer = (byte[]) runtime.newNonMovableArray(byte.class, capacity + 7);
    allocatedAddress = runtime.addressOf(buffer);

    // Offset is set to handle the alignment: http://b/16449607
    offset = (int) (((allocatedAddress + 7) & ~(long) 7) - allocatedAddress);
    isAccessible = true;
    isFreed = false;

【问题讨论】:

长度是属性而不是函数。 尝试使用capacity()。您通常甚至不能保证array() 不会抛出UnsupportedOperationException,因为您的ByteBuffer 往往没有可访问的byte[] 支持。 frameRGBABuffer.array() 不抛出异常,我可以通过“frameRGBABuffer.array()[0]”打印其中的数据 【参考方案1】:

这是它背后的代码(JVM,不是 android,但可能在 Android 上类似):

 DirectByteBuffer(int cap)                    // package-private

    super(-1, 0, cap, cap);
    boolean pa = VM.isDirectMemoryPageAligned();
    int ps = Bits.pageSize();
    long size = Math.max(1L, (long)cap + (pa ? ps : 0)); <----- HERE
    Bits.reserveMemory(size, cap);

    long base = 0;
    try 
        base = unsafe.allocateMemory(size);
     catch (OutOfMemoryError x) 
        Bits.unreserveMemory(size, cap);
        throw x;
    
    unsafe.setMemory(base, size, (byte) 0);
    if (pa && (base % ps != 0)) 
        // Round up to page boundary
        address = base + ps - (base & (ps - 1));
     else 
        address = base;
    
    cleaner = Cleaner.create(this, new Deallocator(base, size, cap));
    att = null;

VM.isDirectMemoryPageAligned()

// User-controllable flag that determines if direct buffers should be page
// aligned. The "-XX:+PageAlignDirectMemory" option can be used to force
// buffers, allocated by ByteBuffer.allocateDirect, to be page aligned.

这是用于性能的低级内容。

根据这位研究人员的说法,这对最近的英特尔 CPU 来说太过分了。 在这里阅读更多:https://lemire.me/blog/2012/05/31/data-alignment-for-speed-myth-or-reality/

【讨论】:

注意:我使用我的 IDE 快速浏览相关代码(+ JavaDocs)。我建议您配置您的 IDE 或编辑器,这样您就可以探索感兴趣的 JDK 代码,而无需通过 Google 或 *** 进行搜索。 得到,谢谢。看了Android的源码,逻辑类似

以上是关于为啥 DirectByteBuffer.array() 有额外的大小?的主要内容,如果未能解决你的问题,请参考以下文章

为啥使用 glTranslatef?为啥不直接更改渲染坐标?

为啥 DataGridView 上的 DoubleBuffered 属性默认为 false,为啥它受到保护?

为啥需要softmax函数?为啥不简单归一化?

为啥 g++ 需要 libstdc++.a?为啥不是默认值?

为啥或为啥不在 C++ 中使用 memset? [关闭]

为啥临时变量需要更改数组元素以及为啥需要在最后取消设置?