2011-10-28 11 views
6

Estoy luchando por comprender la documentación de sun.misc.Unsafe - supongo que no es para uso general, nadie se molesta en hacerlo legible, pero en realidad necesito una forma de encontrar la dirección de un elemento en una matriz (para que pueda pasarle un puntero al código nativo). Alguien tiene un código de trabajo que hace esto? ¿Es confiable?Uso de sun.misc.Unsafe para obtener la dirección de los elementos de la matriz de Java?

+0

http://stackoverflow.com/questions/5574241/interesting-uses-of-sun-misc-unsafe –

+0

[Por qué los desarrolladores no deben escribir programas That Call 'sun' Packages] (http://www.oracle .com/technetwork/java/faq-sun-packages-142232.html) – BalusC

+0

imo, el documento inseguro es bastante bueno, de todos modos no está destinado al público en general. si necesita algunas pautas, comience a leer java.util.concurrent y java.util.concurrent.atomic ... inseguro es bastante cercano a C (o ensamblador, si lo prefiere). Si no tiene ninguna experiencia, no es seguro para usted. Cómo obtener el desmontaje de su código java: http://wikis.sun.com/display/HotSpotInternals/PrintAssembly – bestsss

Respuesta

6

En lugar de utilizar una matriz, puede utilizar un búfer directo ByteBuffer.allocateDirect(). Esto tiene la dirección en un campo y esta dirección no cambia durante la vida del ByteBuffer. Un ByteBuffer directo utiliza un espacio de montón mínimo. Puede obtener la dirección usando reflexión.


Puede utilizar Unsafe para obtener una dirección, el problema es que el GC puede moverlo en cualquier momento. Los objetos no están arreglados en la memoria.

En JNI puede usar métodos especiales para copiar datos en/desde objetos Java para evitar este problema (y otros) Sugiero que los use si desea intercambiar datos entre Objetos con código C.

+1

Prefiero no usar un búfer de byte directo (lo que haría la solución del problema bastante fácil) ya que estoy atascado tratando de implementar una API existente que se define en términos de matrices de bytes, y estoy tratando de evitar la penalización de copiar a y de un conjunto extra de búferes. Esto sería suficiente como último recurso, pero debe haber una forma mejor. Trabajar con JNI lo haría más fácil, pero desafortunadamente estoy trabajando con JNA, que no parece tener las interfaces necesarias para hacer otra cosa que no sea trabajar con arreglos completos. – Jules

+0

@Jules, JNI causará una copia por sí mismo, a menos que desee ir con w/'GetPrimitiveArrayCritical', lo que podría dañar el GC. Muerde la bala y copia en la memoria directa (buffer). Esa es la única solución factible. Por ejemplo, el Impl. FileOutputStream (SocketOutputStream lo extiende) usa una copia de los elementos en la pila. La multa por copiar no es tan alta, ya que el costo más alto se obtiene con el costo de carga de los datos (y el caché falla, incluso) que tendría que pagar de cualquier manera. La copia también provocará la captación previa de las líneas de caché, por lo que podría ser incluso mejor implementar cómo funciona el código nativo. – bestsss

+0

@Jules, en una nota al margen: incluso javax.net.ssl.SSLEngine permite el uso de búferes, todos los algoritmos son byte [] y terminan copiando búferes directos en matrices temporales, esta es la historia inversa y la moraleja de esto : no use búferes directos con SSLEngine. – bestsss

6

Aquí hay una muestra de trabajo. Sin embargo, tenga cuidado ya que puede bloquear fácilmente su JVM con un uso inapropiado de la clase Unsafe.

import java.lang.reflect.Field; 

import sun.misc.Unsafe; 

public class UnsafeTest { 

    public static void main(String... args) { 
     Unsafe unsafe = null; 

     try { 
      Field field = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); 
      field.setAccessible(true); 
      unsafe = (sun.misc.Unsafe) field.get(null); 
     } catch (Exception e) { 
      throw new AssertionError(e); 
     } 

     int ten = 10; 
     byte size = 1; 
     long mem = unsafe.allocateMemory(size); 
     unsafe.putAddress(mem, ten); 
     long readValue = unsafe.getAddress(mem); 
     System.out.println("Val: " + readValue); 

    } 
} 
+2

Ese código debe ser perfectamente seguro, ya que es exactamente como funciona DirectByteBuffer. Lamentablemente, no hace lo que quiero, que es acceder a los datos en una matriz existente. – Jules

+4

@StephenC, el código está perfectamente bien, es básicamente 'char * mem = malloc (tamaño); ...' nunca es tocado por el GC y causa una fuga de C nativa a menos que se restablezca. – bestsss

+2

El código está bien, pero también debe considerar liberar la memoria asignada. Vea DirectByteBuffer para una forma de hacerlo. Tenga en cuenta también que la memoria asignada no está puesta a cero, por lo que no puede suponer que su matriz directa se inicializa en cero. –

1

¿Por qué? Hay muchas instalaciones en JNI para tratar con los contenidos de las matrices de Java. No necesita usar clases Sun internas no documentadas que podrían no estar allí la próxima semana.

+0

Estoy usando JNA, en lugar de JNI, y la función con la que estoy interactuando necesita tener un puntero pasado al centro de una matriz, mientras que JNA solo parece ser capaz de producir un puntero al inicio de una matriz. – Jules

+0

@Jules, no mezcle JNA y arreglos normales, use búferes directos. – bestsss

Cuestiones relacionadas