2011-03-11 8 views
13

Sé que esta es una pregunta extraña para hacer en Java, , pero ¿hay alguna forma de que la asignación de memoria dinámica de Java se alinee con algunas restricciones de alineación? Por ejemplo, ¿es posible asignar dinámicamente objetos que están alineados con el tamaño de página?Alineación de asignación de memoria Java

La razón por la que quiero hacer esto es porque voy a acceder al objeto Java desde el código nativo a través de la interfaz JNI, y la biblioteca de código nativo requiere que el objeto esté alineado.

Gracias.

+0

Tendrás que jugar con ByteBuffer.AllocateDirect(). –

Respuesta

7

No, no es posible. Tenga en cuenta que los objetos en el montón en Java pueden moverse durante la recolección de basura. Tiene algunas opciones:

  1. Detenga el acceso a objetos Java directamente desde JNI. Copie lo que le importa en un búfer provisto por JNI que el código nativo ya haya alineado.
  2. Use ByteBuffer.allocateDirect(). Luego encuentra una región de tu buffer que esté correctamente alineada. Una forma de hacerlo es asignar el búfer al inicio e intentar repetidamente la operación sensible de alineación en diferentes desplazamientos hasta que funcione. Esto es un truco!
+0

Para explicar un poco más, el "buffer provisto por JNI" debería ser alguna región de memoria asignada con 'posix_memalign' (o similar) y envuelta con' NewDirectByteBuffer' de JNI. Devuelve este 'ByteBuffer' al código de Java. Java puede acceder a elementos de Buffers (ByteBuffers, FloatBuffers, etc.) tan rápido como accede a las matrices. Pero recuerde que luego libere esta memoria manualmente en código nativo. –

+2

La asignación y el intento repetidos de la operación es un * hack * hack, que puede provocar fácilmente un bloqueo o un ciclo sin fin. Vea la respuesta de Nitsan para un mejor enfoque. –

1

No hay opciones bonitas, así que aquí van los feos:

Si está utilizando Sun (ahora Oracle) JRE 5.0 o 6.0, puede utilizar el siguiente:

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

Para acceder a los datos en Java, use buffer. Para acceder en JNI, envíe dirección a un puntero. Ambos verán/cambiarán los mismos datos.

Se supone que la dirección debe estar alineada con la página, pero para estar seguro de eso, puede asignar dos páginas (seguramente habrá suficiente espacio para una página completamente alineada). Luego, alinea la dirección en la página y aplica una compensación al acceso de ByteBuffer.

Otra opción para asignación de búfer y llamadas nativas, que funciona en cualquier máquina virtual, es la clase de memoria JNAs: http://jna.java.net/javadoc/com/sun/jna/Memory.html. No se asuste con el paquete com.sun. Es de código abierto y LGPL.

+0

Es una buena idea usar algunos elementos de esta respuesta con el enfoque de Nitsan. A saber, use reflection para obtener la dirección de ByteBuffer en lugar de UnsafeAccess. –

4

Consulte este blog post para una discusión más amplia de la alineación de memoria directa en java que también cubre sus necesidades. Para resumir:

  1. Hasta JDK 1.6 todos los búferes de byte directo están alineados con la página, por lo que si esa es la versión de java que está en su orden.
  2. Desde 1.7 está solo, siga el método descrito en la publicación para obtener un búfer alineado.

le recomiendo que no ir para las asignaciones repetidas hasta llegar a la dirección correcta .. Eso sería muy malo para su software. Si planeas tomar la dirección repetidamente, te recomendaría que la guardes en caché si planeas utilizar el método de reflexión descrito anteriormente. Alternativamente, utilice el método descrito en la publicación usando Unsafe para obtener el valor del campo de dirección.

+0

Esto parece un enfoque razonable, excepto que no utilizaría UnsafeAccess solo para tomar un campo privado. Use reflexión simple (como señaló fernacolo). –

+0

@ AleksandrDubinsky lo suficientemente justo, en el contexto en el que lo estaba usando, iba a abrir el caso de Unsafe de todos modos, pero probablemente no sea el primer puerto de escala ... –

+2

Resulta que también puedes hacer: '((DirectBuffer)) ByteBuffer.allocateDirect (...)). Address() ' –