Java中ByteBuffer与Panama Foreign Memory的性能对比分析
背景
我利用业余时间自学数据库,尝试从零开始实现一个数据库。
首先需要实现的内容之一就是底层数据格式与存储机制。
数据库中存在一种名为“Slotted Page(槽页)”的结构,如下所示:
+-----------------------------------------------------------+ | +----------------------+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ | | | HEADER | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +----------------------+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ | | SLOT ARRAY | | | | | | | | +--------------------+ +----------------+ | | | TUPLE #4 | | TUPLE #3 | | | | | | | | | +--------------------+ +----------------+ | | +--------------------------+ +------------------+ | | | TUPLE #2 | | TUPLE #1 | | | | | | | | | +--------------------------+ +------------------+ | +-----------------------------------------------------------+
页数据通过二进制序列化存储到文件中。槽(Slot)是其中最简单的部分,其定义如下所示:
struct Slot { uint32_t offset; uint32_t length; }
在C++中,读写该结构可通过std::memcpy实现:
// Ignoring offset of header size in below void write_to_buffer(char *buffer, Slot& slot, uint32_t slot_idx) { memcpy(buffer + sizeof(Slot) * slot_idx, &slot.offset, sizeof(uint32_t)); memcpy(buffer + sizeof(Slot) * slot_idx + sizeof(uint32_t), &slot.length, sizeof(uint32_t)); } void read_from_buffer(char *buffer, Slot& slot, uint32_t slot_idx) { memcpy(&slot.offset, buffer + sizeof(Slot) * slot_idx, sizeof(uint32_t)); memcpy(&slot.length, buffer + sizeof(Slot) * slot_idx + sizeof(Slot), sizeof(uint32_t)); }
在Java中,有两种实现方式:
- ByteBuffer方式
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()); } }
- Foreign 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 Slot from(MemorySegment memory) { return new Slot( 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); } }
问题解答
对于Slot这种仅包含两个int字段的简单结构,两种Java实现的性能差异极小,几乎可以忽略不计,完全可以按照你的偏好选择ByteBuffer API,理由如下:
- ByteBuffer的成熟度与优化:作为Java多年来的标准二进制操作API,ByteBuffer(尤其是DirectByteBuffer)经过了大量底层优化,针对基础类型的读写操作已经非常高效,不会成为性能瓶颈。
- Foreign Memory的优势场景:Project Panama引入的Foreign Memory特性,主要优势体现在处理复杂内存布局、大量连续数据访问或者需要直接对接原生内存的场景。对于Slot这种极小的结构,它带来的布局解析开销和ByteBuffer的操作开销几乎没有差别。
- 工程实用性:ByteBuffer的API更通用、生态更完善,调试和维护成本更低,对于你从零实现数据库的场景来说,上手更快,也更容易找到相关参考资料。
内容的提问来源于stack exchange,提问作者Gavin Ray
相关产品推荐
相关产品推荐

