Frage

Wenn ich ein Java-Objekt mit JNI Methoden bauen, um es zu übergeben als Parameter an eine Java-Methode Ich Aufrufe des JNI Aufruf API verwenden, wie verwalte ich seine Erinnerung?

Hier ist, was ich arbeite mit:

Ich habe ein C Objekt, das eine destructor Methode hat, die komplexe dass free() ist. Dieses C-Objekt ist mit einem Java-Objekt zugeordnet werden, und wenn die Anwendung mit dem Java-Objekt fertig ist, hat ich keine Notwendigkeit mehr für das C-Objekt.

Ich schaffe das Java-Objekt wie so (Fehler für Klarheit elided Prüfung):

c_object = c_object_create ();
class = (*env)->FindClass (env, "my.class.name");
constructor = (*env)->GetMethodID (env, class, "<init>", "(J)V");
instance = (*env)->NewObject (env, class, constructor, (jlong) c_object);

method = (*env)->GetMethodID (env, other_class, "doSomeWork", "(Lmy.class.name)V");
(*env)->CallVoidMethod (env, other_class, method, instance);

So, jetzt, dass ich mit instance fertig bin, was soll ich tun damit? Im Idealfall würde Ich mag die Garbage-Collection bis zur VM verlassen; wenn es mit instance getan wäre es fantastisch, wenn es auch c_object_destroy() auf den Zeiger rief ich ihm zur Verfügung gestellt. Ist das möglich?

Eine separate, aber verwandte Frage hat mit dem Umfang von Java Entitäten zu tun, die ich in einem Verfahren wie diesen zu schaffen; muss ich manuell lösen, sagen wir, class, constructor oder method oben? Die JNI doc frustrierende vage ist (meines Erachtens) über das Thema der richtigen Speicherverwaltung.

War es hilfreich?

Lösung

Es gibt ein paar Strategien zum Regenerieren von nativen Ressourcen (Objekte, Datei-Deskriptoren, etc.)

  1. Invoke eine JNI-Methode bei der Finalisierung (), die die Ressource freigibt. Einige Leute empfehlen gegen Umsetzung abzuschließen, und im Grunde kann man nicht wirklich sicher sein, dass Ihre Mutter Ressource jemals befreit. Für Ressourcen wie Speicher ist dies wahrscheinlich kein Problem, aber wenn Sie eine Datei zum Beispiel haben, die mit einer vorhersagbaren Zeit gespült werden muss, finalisieren () wahrscheinlich keine gute Idee.

  2. Sie manuell eine Bereinigungsmethode aufzurufen. Dies ist nützlich, wenn Sie einen Punkt in der Zeit, wo Sie wissen, dass die Ressource gereinigt werden muß. Ich benutzte diese Methode, wenn ich eine Ressource hatte, die ausgeplant werden mussten, bevor sie eine DLL in dem JNI Code Entladen. Um die DLL zu später zu ermöglichen, neu geladen werden, musste ich sicher sein, dass das Objekt wirklich, bevor Sie freigegeben wurde, die DLL zu entladen. Mit nur finalisieren (), würde ich das nicht garantiert bekommen hat. Dies kann mit (1) kombiniert werden, um die Ressource zu ermöglichen, zugeordnet entweder während Finalisierung werden () oder an der manuell Bereinigungsverfahren bezeichnet. (Sie wahrscheinlich eine kanonische Abbildung von WeakReferences müssen verfolgen, welche Bedürfnisse Objekte ihre Bereinigungsmethode aufgerufen haben.)

  3. Angeblich soll die PhantomReference verwendet werden kann, um dieses Problem auch zu lösen, aber ich bin mir nicht sicher, wie genau eine solche Lösung funktionieren würde.

Eigentlich muss ich mit Ihnen auf der JNI Dokumentation nicht einverstanden sind. Ich finde die JNI-Spezifikation ausnahmsweise auf den meisten wichtigen Fragen klar, auch wenn die Abschnitte über die lokalen und globalen Referenzen Verwaltung könnte mehr gewesen erarbeitet.

Andere Tipps

Die JNI-Spezifikation deckt die Frage, wer "besitzt" Java-Objekte in JNI Methoden erstellt hier . Sie müssen zwischen local und global Verweise unterscheiden.

Wenn die JVM eine JNI rufen zu nativen Code macht, setzt er einen Registry-up Überblick über alle Objekte während des Gesprächs angelegt zu halten. Jedes Objekt in dem nativen Aufruf erzeugt (das heißt von einer JNI-Schnittstelle Funktion zurückgegeben) werden zu dieser Registrierung hinzugefügt. Verweise auf solche Objekte sind bekannt als lokale Referenzen . Wenn die native Methode der JVM zurückgibt, alle lokalen Referenzen während der nativen Methodenaufruf erstellt werden zerstört. Wenn Sie Anrufe zurück in die JVM während eines nativen Methodenaufrufes zu machen, wird die lokale Referenz noch am Leben sein, wenn die Steuerung auf die native Methode gibt zurück. Wenn die JVM von nativen Code aufgerufen weiteren Anruf zurück in den nativen Code machen, wird eine neue Registrierung von lokalen Referenzen erstellt, und die gleichen Regeln gelten.

(In der Tat können Sie implementieren sind Sie eigene JVM ausführbar (dh java.exe) die JNI-Schnittstelle, durch eine JVM zu schaffen (und dadurch einen JNIEnv * Zeiger) empfängt, die Klasse auf der Kommandozeile angegeben aufzublicken, und Aufrufen der Methode main () darauf.)

Alle Referenzen von JNI-Schnittstelle Methoden zurückgegeben werden lokale . Dies bedeutet, dass unter normalen Umständen Sie müssen nicht manuell Referenzen von JNI Methoden geben ausplanen, da sie zerstört werden, wenn der JVM zurück. Manchmal möchte man immer noch, sie zerstören „vorzeitig“, zum Beispiel, wenn Sie viele lokale Referenzen, die Sie auf die JVM löschen möchten vor der Rückkehr.

Globale Referenzen werden erstellt (von lokalen Referenzen) durch die NewGlobalRef () verwenden. Sie werden zu einem speziellen Register hinzugefügt und werden manuell freigegeben werden. Globale Referenzen werden nur für Java-Objekt verwendet, die der nativen Code einen Verweis auf über mehrere JNI nennen, zum Beispiel zu halten braucht, wenn Sie native Code haben auslösende Ereignisse, die zurück zu Java propagiert werden sollen. In diesem Fall muss der JNI Code einen Verweis auf ein Java-Objekt speichern, die das Ereignis zu empfangen ist.

Hope dies verdeutlicht die Speicherverwaltung Problem ein wenig.

Re: „Eine separate, aber miteinander verbundene Frage“ ... Sie müssen nicht manuell JClass, jfieldID und jmethodID lösen, wenn man sie in einem „lokalen“ Kontext verwenden. Alle Ähnlichkeiten Objektreferenzen Sie erhalten (nicht JClass, jfieldID, jmethodID) sollten mit DeleteLocalRef freigegeben werden.

Die GC würde Ihre Instanz sammeln, aber es wird den Nicht-Java-Heap-Speicher in dem nativen Code zugewiesen nicht automatisch freigeben. Sie sollten in der Klasse explizite Methode haben die c_object Instanz freizugeben.

Dies ist einer der Fälle, wo ich würde empfehlen, einen Finalizer mit Überprüfung, ob c_object und es veröffentlicht wurde, freigeben, eine Nachricht protokolliert wird, wenn es nicht.

Eine nützliche Technik ist eine Throwable Instanz in dem Java-Klasse Konstruktor zu erstellen und speichern sie in einem Feld (oder nur das Feld inline initialisieren). Wenn der Finalizer feststellt, dass die Klasse ordnungsgemäß entsorgt wurde nicht würde es den Stacktrace drucken, die Zuordnung Stapel ausfindig.

Ein Vorschlag ist, tun gerade JNI zu vermeiden und gehen mit gluegen oder Swig (beide Code erzeugen und statisch verknüpft werden können).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top