【问题标题】:Is there a way to create a direct ByteBuffer from a pointer solely in Java?有没有办法仅在 Java 中从指针创建直接 ByteBuffer?
【发布时间】:2013-05-09 15:29:30
【问题描述】:

或者我是否必须有一个调用 env->NewDirectByteBuffer(buffer, size) 的 JNI 辅助函数?

【问题讨论】:

  • 你看过 sun.misc.unsafe 吗?它允许您直接与内存交互。
  • 我确实看过,但没有看到使用 sun.misc.unsafe 创建直接字节缓冲区的方法。我确实找到了一种创建 DirectByteBuffer 的方法,它是通过反射。使用 java.lang.Class.getDeclaredConstructor 创建一个 Constructor 对象,setAccessable 为 true 并使用适当的参数调用 newInstance。有点笨拙,但您不必编写任何 JNI 代码。

标签: java jvm bytebuffer


【解决方案1】:

我所做的是创建一个普通的 DirectByteBuffer 并更改它的地址。

Field address = Buffer.class.getDeclaredField("address");
address.setAccessible(true);
Field capacity = Buffer.class.getDeclaredField("capacity");
capacity.setAccessible(true);

ByteBuffer bb = ByteBuffer.allocateDirect(0).order(ByteOrder.nativeOrder());
address.setLong(bb, addressYouWantToSet);
capacity.setInt(bb, theSizeOf);

从这里您可以访问引用底层地址的 ByteBuffer。我这样做是为了访问网络适配器上的内存以进行零拷贝,并且效果很好。

您可以直接为您的地址创建一个 DirectByteBuffer,但这更加晦涩。


另一种方法是使用 Unsafe(这仅适用于 OpenJDK/HotSpot JVM 和本机字节顺序)

Unsafe.getByte(address);
Unsafe.getShort(address);
Unsafe.getInt(address);
Unsafe.getLong(address);

【讨论】:

  • 很好的答案,但是我不得不对其进行一些修改才能使其正常工作,特别是 Field address = Buffer.class.getDeclaredField("address")。
  • 所以这是对原始问题的跟进,因为您仍在关注。以这种方式清理附加到 ByteBuffer 的内存的最佳方法是什么? ByteBuffer 会最终确定空闲地址还是调用者应该干预并清理分配?出于这个问题的目的,假设我已经编写了一个 JNI 库,其中包含 malloc 和 free 的包装器:) 现在我已经考虑了更多,可能值得提出这个问题。
  • @Erik 创建了内存应该释放它。如果你需要调用一个特殊的方法,你需要设置一个 Cleaner,它可以被确定性地调用,也可以在 GC 时调用。
  • @Erik 在 Chronicle Bytes 中我们有自己的 64 位内存包装器和附加功能。我们还具有引用计数功能,以允许按需释放内存,并在未释放内存时使用 Cleaner。
  • 感谢您的快速回复!我将阅读 Cleaner(我是一名 C 程序员,被要求做 Java 工作,试图快速启动)。
猜你喜欢
  • 1970-01-01
  • 2019-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-25
  • 1970-01-01
相关资源
最近更新 更多