2011-08-16 19 views
9

Tener un vistazo a la documentación JNI aquí: http://download.oracle.com/javase/1.5.0/docs/guide/jni/spec/functions.htmlJNI EnsureLocalCapacity - WHY?

Específicamente, mira lo que se dice en la descripción de la función EnsureLocalCapacity:

Para compatibilidad con versiones anteriores, la máquina virtual asigna referencias locales más allá de el asegurado capacidad. (Como soporte de depuración, la VM puede dar al usuario avisos de que se están creando demasiadas referencias locales. En el JDK, el programador puede suministrar la opción de línea de comando -verbose: jni a activar estos mensajes). llama a FatalError si no se pueden crear más referencias locales más allá de la capacidad asegurada.

Y, además, observe cómo PushLocalFrame toma un argumento de "capacidad". (Y por cierto, no menciona si esto es un límite difícil, o un límite suave como con EnsureLocalCapacity).

Dónde se encuentra exactamente todas estas tonterías acerca de la capacidad local de referencia viene? Los documentos dicen que VM estará dispuesta a asignar referencias más allá de la capacidad formal actual, ¿por qué no lo hace y mantiene toda esta capacidad desordenada de la API?

Para dar una analogía a C, se siente como si me pidieran pre-planificar cuántas llamadas malloc() voy a hacer, y se siente un poco ridículo.

¿Hay algo importante que no estoy viendo aquí?

Respuesta

0

Ésta es mi suposición. Sospecho que el crecimiento de la capacidad de referencia local es costoso y esta función permite solicitar la capacidad deseada una vez por cada invocación de método nativo. Creo que se trata más de rendimiento que de corrección.

0

A mi entender el tamaño local de la tabla de referencia es predefinida, y si asigna más de que simplemente se colgará. Entonces, no es que VM le dará más referencias locales para siempre. Me he encontrado con esto muchas veces mientras trabajaba con JNI en Android. A menudo es difícil encontrar dicha pérdida de memoria. Y al llamar a env-> DeleteLocalRef() cada vez que haces algo con las referencias locales de JNI, se satura el código. Entonces, en lugar de saturar el código con llamadas DeleteLocalRef(), podemos asegurarnos de no crear demasiadas referencias y mantener el código bastante limpio. E incluso si planeamos asignar muchas más referencias locales, aún podemos llamar a PushLocalFrame()/PopLocalFrame() y evitar muchas llamadas a DeleteLocalRef().

a que den a usted analogía, se le pedirá "C" para pre-plan de llamadas a malloc para evitar todas las llamadas necesarias para liberar() al final.

0

La documentación de JNI es blanda sobre este tema. En la práctica, he descubierto que, en ocasiones, el número de referencias locales parece ilimitado, pero en realidad puede quedarse sin referencias locales, por ejemplo, al iterar sobre una matriz utilizando llamadas JNI. ¿Qué es una referencia local?Es un jobject (o jarray, jstring, etc) que se obtiene de cualquiera de estas fuentes:

  • de regresar de una llamada JNI prima como NewObjectV() o GetObjectArrayElement()
  • de regresar de una llamada a un método como CallObjectMethodV()
  • pasados ​​a la función nativa como argumento
  • Probablemente otros que he olvidado

de éstos, por lo general, no necesita preocuparse por las referencias que se pasan a usted en un método de ar gument, A MENOS que tenga la intención de mantener la referencia más allá de la llamada al método actual, en cuyo caso debe convertirla a global.

Vale la pena señalar que no debe aferrarse a una referencia local fuera del alcance del método actual. Si va a almacenarlo en un objeto C++, debe convertirlo a global. Las referencias locales tienen dos ventajas

  1. Se liberan siempre automáticamente cuando el marco actual está fuera del alcance.
  2. Ellos son más rápidos que la conversión a lo global

Como la mayoría de los errores de JNI, cualquier mal uso de las referencias son horribles para diagnosticar, por lo que realmente no desea conseguir uno. Tu mejor defensa es un enfoque consistente. En mi experiencia, el costo de convertir de local a global es bastante pequeño. Sugeriría lo siguiente, a menos que tenga necesidades de rendimiento muy estrictas.
Teniendo en cuenta que, mi regla es - convertir SIEMPRE árbitros locales para árbitros globales, utilizando código como:

jobject localjo = ... 
jobject globaljo = env->NewGlobalRef(localjo); 
env->DeleteLocalRef(localjo); 

En ese momento, se puede saber que cada ref es global, y cuando haya terminado, es necesario para recordar hacer env-> DeleteGlobalRef (globaljo) en cada uno. En C++ es posible escribir una clase contenedora alrededor de las referencias JNI que llama a env-> DeleteGlobalRef() en dtor. Pero como JNI no hace referencia a las referencias de JNI para usted, es posible que también tenga que compilarlo.