2011-08-16 18 views
9

Avere esaminare le documentazione JNI qui: http://download.oracle.com/javase/1.5.0/docs/guide/jni/spec/functions.htmlJNI GuaranteLocalCapacity - PERCHÉ?

particolare, guarda quanto detto nella descrizione della funzione EnsureLocalCapacity:

Per compatibilità all'indietro, il VM alloca riferimenti locali oltre l'assicurato capacità. (Come supporto per il debug, la VM può dare agli avvisi utente la creazione di troppi riferimenti locali. Nel JDK , il programmatore può fornire l'opzione -verbose: jni command line a attivare questi messaggi.) La VM chiama FatalError se non è possibile creare più riferimenti locali oltre la capacità garantita.

E inoltre, guarda come PushLocalFrame accetta un argomento di "capacità". (E dal modo in cui non menziona se questo è un limite rigido, o un limite soft come con EnsureLocalCapacity).

Dove si trova esattamente tutta questa assurdità sulla capacità di riferimento locale? I documenti dicono che VM sarà disposta ad allocare referenze al di là dell'attuale capacità formale, quindi perché non lo fa e mantiene tutta questa confusione di capacità fuori dall'API?

Per dare un'analogia con C, sembra che mi venga chiesto di pianificare in anticipo quante chiamate di malloc() ho intenzione di creare, e mi sembra un po 'ridicolo.

C'è qualcosa di importante che non vedo qui?

risposta

0

Questa è la mia indovina. Sospetto che la crescente capacità di riferimento locale sia costosa e questa funzione consente di richiedere la capacità desiderata una volta per invocazione del metodo nativo. Penso che si tratti più delle prestazioni che della correttezza.

0

A mio avviso, la dimensione della tabella di riferimento locale è predefinita e se si assegna più di quella si bloccherà. Quindi non è che VM ti darà più refs locali per sempre. L'ho incontrato molte volte mentre lavoravo con JNI su Android. È spesso difficile trovare tale perdita di memoria. E chiamare env-> DeleteLocalRef() ogni volta che si fa qualcosa con i riferimenti locali JNI limita il codice. Quindi, invece di ingombrare il codice con chiamate DeleteLocalRef(), possiamo semplicemente assicurarci di non creare troppi riferimenti e di mantenere il codice abbastanza pulito. E anche se pianifichiamo di allocare molti più riferimenti locali, possiamo comunque chiamare PushLocalFrame()/PopLocalFrame() ed evitare molte chiamate a DeleteLocalRef().

Quindi, per fornire l'analogia a "C", viene richiesto di pianificare in anticipo le chiamate a malloc per evitare tutte le chiamate necessarie a free() alla fine.

0

La documentazione JNI è insignificante su questo argomento. Ho trovato in pratica che a volte il numero di ref locali sembra illimitato, ma in realtà è possibile esaurire i riferimenti locali, ad esempio durante l'iterazione su un array usando le chiamate JNI. Cos'è un riferimento locale?Si tratta di una jobject (o jarray, jstring, ecc) che si ottiene da una qualsiasi di queste fonti:

  • restituito da una chiamata JNI cruda come NewObjectV() o GetObjectArrayElement()
  • tornato da una chiamata di metodo come CallObjectMethodV()
  • Passato alla funzione nativa come argomento
  • Probabilmente altri che ho dimenticato

di questi, di solito non è necessario preoccuparsi i riferimenti che sono passati a voi in un metodo ar a meno che non intendiate mantenere il riferimento oltre la chiamata al metodo corrente, nel qual caso dovreste convertirlo in globale.

Vale la pena notare che non è necessario aggrapparsi a un riferimento locale al di fuori dell'ambito del metodo corrente. Se lo si memorizza in un oggetto C++, è necessario convertirlo in globale. I riferimenti locali hanno due vantaggi

  1. Vengono sempre rilasciati automaticamente quando il frame corrente non rientra nell'ambito.
  2. Sono più veloce di conversione al globale

Come la maggior parte degli errori JNI, ogni abuso di riferimenti sono orribili da diagnosticare, in modo che davvero non si vuole ottenere uno. La tua migliore difesa è un approccio coerente. Secondo la mia esperienza, il costo di conversione da locale a globale è piuttosto ridotto. Suggerirei quanto segue, a meno che non si abbiano esigenze di prestazioni molto rigide.
Dato che, la mia regola è - SEMPRE convertire arbitri locali per arbitri globali, utilizzando il codice come:

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

A quel punto, si può sapere che ogni ref è globale, e quando si è fatto, è necessario per ricordare di fare env-> DeleteGlobalRef (globaljo) su ognuno. In C++ è possibile scrivere una classe wrapper attorno ai riferimenti JNI che chiama env-> DeleteGlobalRef() nel dtor. Ma dal momento che JNI non fa riferimento, conta i riferimenti JNI per te, potrebbe essere necessario crearlo anche in questo.