繁体   English   中英

Java:ByteBuffer 与 jdk.incubator.foreign(巴拿马)的性能 国外 Memory 方法(MemoryLayout/Segment)

[英]Java: Performance of ByteBuffer versus jdk.incubator.foreign (Panama) Foreign Memory methods (MemoryLayout/Segment)

背景

我在业余时间自学数据库,试图通过实施一个从头开始来学习。

您必须实现的第一件事是底层数据格式和存储机制。

在 DB 中,有一个称为“Slotted Page”的结构,如下所示:

+-----------------------------------------------------------+
| +----------------------+  +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ |
| | HEADER               |  | | | | | | | | | | | | | | | | |
| |                      |  | | | | | | | | | | | | | | | | |
| +----------------------+  +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ |
|                                     SLOT ARRAY            |
|                                                           |
|                                                           |
|                                                           |
|                 +--------------------+ +----------------+ |
|                 |  TUPLE #4          | |  TUPLE #3      | |
|                 |                    | |                | |
|                 +--------------------+ +----------------+ |
|         +--------------------------+ +------------------+ |
|         |  TUPLE #2                | |  TUPLE #1        | |
|         |                          | |                  | |
|         +--------------------------+ +------------------+ |
+-----------------------------------------------------------+

页面数据通过二进制序列化存储到文件中。 插槽是最简单的部分,其定义可能如下所示:

struct Slot {
  uint32_t offset;
  uint32_t length;
}

在 C++ 中,读/写的过程可能是std::memcpy

void write_to_buffer(char *buffer, Slot& slot) {
  memcpy(buffer + slot.offset, &slot.length, sizeof(uint32_t));
  memcpy(buffer + slot.offset + sizeof(uint32_t), &slot.length, sizeof(uint32_t));
}

void read_from_buffer(char *buffer, Slot& slot) {
  memcpy(&slot.offset, buffer + slot.offset, sizeof(uint32_t));
  memcpy(&slot.length, buffer + slot.offset + sizeof(uint32_t), sizeof(uint32_t));
}

在 Java 中,据我所知,您可以执行以下两种操作之一:

  1. 字节缓冲区
record Slot(int offset, int length) {
    void write(ByteBuffer buffer) {
        buffer.putInt(offset).putInt(length);
    }
    
    static Slot read(ByteBuffer buffer) {
        return new Slot(buffer.getInt(), buffer.getInt());
    }
}
  1. 全新国外memory东东
record Slot(int offset, int length) {
    public static MemoryLayout LAYOUT = MemoryLayout.structLayout(
            ValueLayout.JAVA_INT.withName("offset"),
            ValueLayout.JAVA_INT.withName("length"));

    public static TupleSlot from(MemorySegment memory) {
        return new TupleSlot(
                memory.get(ValueLayout.JAVA_INT, 0),
                memory.get(ValueLayout.JAVA_INT, Integer.BYTES));
    }

    public void to(MemorySegment memory) {
        memory.set(ValueLayout.JAVA_INT, 0, offset);
        memory.set(ValueLayout.JAVA_INT, Integer.BYTES, length);
    }
}

这些之间的性能差异是什么?

如果可以忽略不计,我更喜欢 ByteBuffer API。

panama-dev邮件列表中回复 Paul Sandoz 的回复:

嗨,加文,

与 ByteBuffer 相比,使用 MemorySegment 将使您对描述(布局)和管理(释放和池化)有更多的控制。 此外,如果这是一个问题,您也不会受到 ByteBuffer 大小限制的限制。 使用 MemorySegment 在性能方面应该与 ByteBuffer 一样好或更好。

在许多方面 MemorySegment 是更好的 API 与原生 memory 交互。 ByteBuffer 是在 Java 1.4 中与 NIO 一起引入的,并且考虑到了今天不太相关的其他设计约束(例如内部可变索引)。

保罗。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM