Copia y fijación

En cualquier momento la recopilación de basura puede decidir que necesita compactar el almacenamiento dinámico de elementos recopilados en la basura. La compactación implica mover físicamente los objetos de una dirección a otra. Estos objetos podrían tener una referencia de JNI local o global. Para que la compactación se produzca sin problemas, las referencias JNI no son punteros directos al almacenamiento dinámico. Al menos un nivel de indirección aísla el código nativo frente al movimiento de objetos.

Si un método nativo necesita obtener direccionabilidad directa hacia el interior de un objeto, la situación es más complicada. El requisito para direccionar directamente o fijar el almacenamiento dinámico es habitual cuando es necesario que haya un acceso rápido, compartido a grandes matrices primitivas. Un ejemplo podría ser un almacenamiento intermedio de pantalla. En estos casos, se puede utilizar una sección crítica de JNI, que impone requisitos adicionales al programador, según se especifica en la descripción de JNI para estas funciones. Para obtener detalles, consulte la especificación de JNI.

  • GetPrimitiveArrayCritical devuelve la dirección de almacenamiento dinámico directa de una matriz Java™ , inhabilitando la recogida de basura hasta que se llame al ReleasePrimitiveArrayCritical correspondiente.
  • GetStringCritical devuelve la dirección de almacenamiento dinámico directo de una instancia java.lang.String inhabilitando la recopilación de basura hasta que se llama a ReleaseStringCritical.

Todas las demás interfaces Gett<PrimitiveType>ArrayElements devuelven una copia que no se ve afectada por la compactación.

Cuando se utiliza la política de recogida de basura equilibrada, es posible que los formularios *Critical de las llamadas no devuelvan un puntero directo al almacenamiento dinámico, lo que se refleja en el distintivo isCopy . Este comportamiento se debe a una representación interna de matrices más grandes, donde los datos podrían no ser secuenciales. Normalmente, una matriz con almacenaje inferior a 1/1000 del almacenamiento dinámico, devuelve un puntero directo.

Utilización del distintivo isCopy

Las funciones de JNI Get<Type> especifican un parámetro de salida de paso por referencia (jboolean * isCopy) que permite al llamador determinar si una llamada JNI determinada devuelve la dirección de una copia o la dirección del objeto fijado en el almacenamiento dinámico.

Las funciones Get<Type> y Release<Type> vienen en pares:

  • GetStringChars y ReleaseStringChars
  • GetStringCritical y ReleaseStringCritical
  • GetStringUTFChars y ReleaseStringUTFChars
  • Get<PrimitiveType>ArrayElements y Release<PrimitiveType>ArrayElements
  • GetPrimitiveArrayCritical y ReleasePrimitiveArrayCritical

Si se pasa una dirección no nula como el parámetro isCopy, la función JNI establece el valor jboolean de esa dirección en JNI_TRUE si la dirección devuelta es una copia de los elementos de matriz, y devuelve JNI_FALSE si la dirección apunta directamente al objeto fijado en el almacenamiento dinámico.

A excepción de las funciones críticas, la máquina virtual J9 siempre devuelve una copia. La copia facilita la carga del recopilador de basura porque los objetos fijados no se pueden compartir y complican la desfragmentación.

Para evitar fugas de memoria, es necesario:

  • Gestione la memoria de copia usted mismo mediante las funciones Get<Type>Region y Set<Type>Region.
  • Asegúrese de liberar copias realizadas por una función Get<Type> llamando a la función Release<Type> correspondiente cuando la copia ya no sea necesaria.

Utilización del distintivo de modalidad

Cuando se llama a Release<Type>ArrayElements, el último parámetro es un distintivo de modalidad. El distintivo de modalidad se utiliza para evitar copias innecesarias en el almacenamiento dinámico de Java cuando se trabaja con una matriz copiada. El distintivo de modalidad se ignora si se trabaja con una matriz que se ha fijado.

Debe llamar a Release<Type> una vez para cada llamada Get<Type>, independientemente del valor del parámetro isCopy. Este paso es necesario porque llamar a Release<Type> suprime las referencias locales de JNI que de otro modo podrían impedir la recogida de basura.

Los valores posibles del distintivo de modalidad son:
0
Actualice los datos en el almacenamiento dinámico de Java. Liberar el espacio ocupado por la copia.
JNI_COMMIT
Actualice los datos en el almacenamiento dinámico de Java. No liberar el espacio ocupado por la copia.
JNI_ABORT
No actualice los datos en el almacenamiento dinámico de Java. Liberar el espacio ocupado por la copia.

El distintivo de modalidad '0' es la opción más segura para la llamada a Release<Type>. Tanto si la copia de los datos se ha cambiado como si no, el almacenamiento dinámico se actualiza con la copia y no hay fugas de memoria.

Para evitar tener que volver a copiar una copia no modificada, utilice el valor de modalidad JNI_ABORT. Si modifica la matriz devuelta, compruebe el distintivo isCopy antes de utilizar el valor de modalidad JNI_ABORT para "retrotraer" los cambios. Este paso es necesario porque una máquina virtual Java de fijación deja el almacenamiento dinámico en un estado diferente del de una máquina virtual Java de copia.

Una forma genérica de utilizar los distintivos isCoypy y de modalidad

A continuación se proporciona una forma genérica de utilizar los distintivos isCopy y de modalidad. Funciona con todas las máquinas virtuales Java y garantiza que se confirman los cambios y no se producen fugas de memoria.

Para utilizar los distintivos de una forma genérica, asegúrese de lo siguiente:
  • No utilice el distintivo isCopy. Pase un valor nulo ó 0.
  • Establezca siempre el distintivo de modalidad en un valor cero.

El uso complicado de estos distintivos sólo es necesario para la optimización. Si utiliza la forma genérica, debe seguir planteándose la sincronización. Consulte Sincronización.