Java内存分配对齐

时间:2011-03-11 01:46:02

标签: java memory-management memory-alignment

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

我想这样做的原因是因为我将通过JNI接口从本机代码访问Java对象,而本机代码库需要对齐对象。

感谢。

3 个答案:

答案 0 :(得分:7)

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

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

答案 1 :(得分:5)

有关java中直接内存对齐的更广泛讨论,请参阅此blog post,其中也涵盖了您的要求。总结一下:

  1. 直到JDK 1.6,所有直接字节缓冲区都是页面对齐的,所以如果这是你所使用的java版本,你就会被排序。
  2. 从1.7开始,您可以按照帖子中列出的方法获取对齐的缓冲区。
  3. 我会建议你不要去重复分配,直到你找到正确的地址。这对你的软件来说非常糟糕。如果您计划重复获取地址,我建议您在计划使用上述反射方法时对其进行缓存。或者,使用不安全的帖子中列出的方法来获取地址字段的值。

答案 2 :(得分: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访问数据,请使用缓冲区。要在JNI中访问,请将地址强制转换为指针。两者都会看到/更改相同的数据。

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

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