16

我知道在 Java 中这是一个奇怪的问题,但是有没有办法让 Java 动态内存分配与一些对齐约束对齐?例如,是否可以动态分配与页面大小对齐的对象?

我之所以要这样做,是因为我要通过JNI接口从native代码访问Java对象,而native代码库要求对象对齐。

谢谢。

4

3 回答 3

8

不,这是不可能的。请记住,Java 中堆上的对象可以在垃圾回收期间四处移动。你有一些选择:

  1. 停止直接从 JNI 访问 Java 对象。将您关心的内容复制到本机代码已经对齐的 JNI 提供的缓冲区中。
  2. 使用ByteBuffer.allocateDirect()。然后找到正确对齐的缓冲区区域。一种方法是在启动时分配缓冲区,并在不同的偏移量处反复尝试对齐敏感操作,直到它工作为止。这是一个黑客!
于 2011-03-11T02:01:40.803 回答
5

有关Java 中直接内存对齐的更广泛讨论,请参阅此博客文章,这也涵盖了您的要求。总结一下:

  1. 直到 JDK 1.6,所有直接字节缓冲区都是页面对齐的,所以如果那是你使用的 java 版本,那么你就会被排序。
  2. 从 1.7 开始,您就靠自己了,请按照帖子中概述的方法获取对齐的缓冲区。

我建议您在找到正确的地址之前不要进行重复分配。这对您的软件非常不利。如果您打算重复获取地址,如果您打算使用上述反射方法,我建议您将其缓存。或者使用文章中概述的方法使用 Unsafe 来获取地址字段的值。

于 2013-01-08T15:08:15.780 回答
2

没有漂亮的选择,所以这里是丑陋的:

如果您使用的是 Sun(现在是 Oracle)JRE 5.0 或 6.0,则可以使用以下内容:

   ByteBuffer buffer = ByteBuffer.allocateDirect(pageSize);
   Method getAddress = buffer.getClass().getMethod("address");
   long address = getAddress.invoke(buffer);
   // and now send address to JNI

要在 Java 中访问数据,请使用buffer。要在 JNI 中访问,请将地址转换为指针。两者都会看到/更改相同的数据。

该地址应该是页面对齐的,但为了确保这一点,您可以分配两个页面(肯定会有足够的空间用于完全对齐的页面)。然后对齐页面上的地址并将偏移量应用于 ByteBuffer 访问。

另一个适用于任何 VM 的缓冲区分配和本机调用选项是使用 JNAs 内存类:http: //jna.java.net/javadoc/com/sun/jna/Memory.html。不要被com.sun包吓到。它是开源的和 LGPL。

于 2011-03-11T02:18:01.327 回答