2008-12-03 18 views
22

¿Cuál es la forma "correcta" de almacenar un puntero nativo dentro de un objeto Java?¿Cuál es la forma "correcta" de almacenar un puntero nativo dentro de un objeto Java?

que podría tratar el puntero como Java int, si me he enterado de que los punteros nativos son < = 32 bits de tamaño, o una aplicación Java long si me he enterado de que los punteros nativos son < = 64 bits de tamaño. ¿Pero hay una forma mejor o más limpia de hacer esto?

Editar: Volviendo un puntero nativa de una función JNI es exactamente lo que No queremos hacer. Preferiría devolver un objeto Java que represente el recurso nativo. Sin embargo, es probable que el objeto Java que devuelva tenga un campo que contenga un puntero, lo que me lleva de vuelta a la pregunta original.

O, alternativamente, ¿hay alguna forma mejor para que una función JNI devuelva una referencia a un recurso nativo?

+0

estrechamente relacionada con la cuestión http://stackoverflow.com/questions/1632367/passing-pointers-between-c-and-java-through-jni – Raedwald

Respuesta

21

IIRC, ambos java.util.zip y java.nio simplemente use long.

+1

+1. Use un largo, ya que el tiempo de ejecución de Java se hace solo. – erickson

+0

usar un objeto que se envuelve por mucho tiempo tiene sobrecarga: puede duplicar el consumo de memoria ya que un objeto puede ocupar al menos 8 bytes sin mencionar que las instancias de su tipo de envoltura tendrán que ser recogidas de basura –

2

Una mejor forma de hacerlo es almacenarla en una matriz de bytes, ya que los punteros nativos no son muy Java-ish en primer lugar. int sy long s están mejor reservadas para almacenar valores numéricos.

2

que suponer que se trata de un puntero de regresar de un cierto código JNI y mi consejo sería simplemente no hacerlo :)

Lo ideal sería que el código JNI debe pasar de vuelta algún tipo de referencia lógica al recurso y no es un puntero real?

En cuanto a su pregunta, no hay nada que le venga a la mente acerca de una forma más limpia de almacenar el puntero; si sabe lo que tiene, utilice int o long o byte [] según sea necesario.

+0

Podría dar un ejemplo de una 'referencia a la lógica recurso'? Edité mi pregunta para aclarar lo que quise decir un poco. –

+0

La referencia lógica sería simplemente un número que retorna el código jni que se usa en llamadas de subsecuentes al jni para hacer referencia a algo. el código jni puede desreferenciar eso a través de algún tipo de estructura, p. una matriz [ref] [puntero]. hth – LenW

+1

Eso significaría mantener una matriz que contiene punteros a cada recurso al que se debe hacer referencia desde Java. No creo que sea una buena idea ... –

0

Puede ver la forma en que C# maneja esto con el tipo de IntPtr. Al crear su propio tipo para sostener punteros, el mismo tipo se puede usar de 32 bits o de 64 bits, dependiendo del sistema en el que se encuentre.

3

No hay una buena manera. En SWT, se utiliza este código:

int /*long*/ hModule = OS.GetLibraryHandle(); 

y hay una herramienta que convierte el código entre 32 y 64 bits moviendo el comentario. Feo, pero funciona. Las cosas habrían sido mucho más fáciles si Sun hubiera agregado un objeto "NativePointer" o algo así, pero no lo hicieron.

3

java.nio.DirectByteBuffer hace lo que quiere.

Internamente usa private long address para almacenar el valor del puntero. Dah!

Utilice la función JNI env->NewDirectByteBuffer((void*) data, sizeof(MyNativeStruct)) para crear un DirectByteBuffer en el lado C/C++ y devolverlo al lado Java como un ByteBuffer. Nota: ¡Es su trabajo liberar estos datos en el lado nativo! Extraña el limpiador automático disponible en DirectBuffer estándar.

Al lado de Java, se puede crear un DirectByteBuffer esta manera:

ByteBuffer directBuff = ByteBuffer.allocateDirect(sizeInBytes); 

creo que como una especie de C de malloc(sizeInBytes). Nota: Tiene como Limpiador automático, que desasigna la memoria solicitada anteriormente.

pero hay algunos puntos a tener en cuenta sobre el uso de DirectByteBuffer:

  • Se puede ser considerado basura (GC) si se olvida de su referencia directa ByteBuffer.
  • Puede leer/escribir valores en una estructura puntiaguda, pero tenga cuidado tanto con el desplazamiento como con el tamaño de los datos. El compilador puede agregar espacios adicionales para el relleno y romper las compensaciones internas asumidas en la estructura. La estructura con punteros (zancada de 4 u 8 bytes?) También confunde sus datos.
  • Direct ByteBuffers son muy fáciles de pasar como un parámetro para los métodos nativos, así como para recuperarlo como devolución.
  • Debe convertir para corregir el tipo de puntero en el lado JNI. El tipo predeterminado devuelto por env->GetDirectBufferAddress(buffer) es void*.
  • No puede cambiar el valor del puntero una vez creado.
  • Es su trabajo liberar memoria previamente asignada para búferes en el lado nativo. Los que usaste con env->NewDirectByteBuffer().
Cuestiones relacionadas