Sehen Sie sich die JNI-Dokumentation hier an: Ссылка
Sehen Sie sich genauer an, was in der Beschreibung der EnsureLocalCapacity-Funktion gesagt wird:
Aus Gründen der Abwärtskompatibilität weist die VM darüber hinaus lokale Referenzen zu die gesicherte Kapazität. (Als Debugging - Unterstützung kann die VM den Benutzerwarnungen, dass zu viele lokale Referenzen erstellt werden. In dem JDK kann der Programmierer die Befehlszeilenoption -verbose: jni zur Verfügung stellen Schalten Sie diese Nachrichten ein.) Die VM ruft FatalError auf, wenn sie nicht mehr lokal ist Referenzen können über die gesicherte Kapazität hinaus erstellt werden.
Und darüber hinaus, wie PushLocalFrame ein "Kapazität" -Argument nimmt. (Und übrigens nicht erwähnt, ob dies eine harte Grenze oder eine weiche Grenze wie bei EnsureLocalCapacity ist).
Woher kommt der ganze Unsinn über die lokale Referenzkapazität? Die Dokumentation sagt, dass VM bereit sein wird, Referenzen über die aktuelle formale Kapazität hinaus zuzuordnen. Warum also nicht einfach so und die ganze Kapazität aus der API streichen?
Um eine Analogie zu C zu geben, fühlt es sich an, als ob ich gefragt werde, wie viele malloc () -Aufrufe ich vorhabe, und es fühlt sich ein bisschen lächerlich an.
Gibt es etwas Wichtiges, das ich hier nicht sehe?
Das ist meine Vermutung . Ich vermute, dass die wachsende lokale Referenzkapazität teuer ist und diese Funktion ermöglicht, die gewünschte Kapazität einmal pro nativem Methodenaufruf anzufordern. Ich denke, es geht mehr um Leistung als um Korrektheit.
Nach meinem Verständnis ist die lokale Referenztabellengröße vordefiniert, und wenn Sie mehr als diese zuweisen, stürzt sie einfach ab. Es ist also nicht so, dass VM dir mehr lokale Refs für immer geben wird. Ich habe dies oft während der Arbeit mit JNI auf Android erlebt. Es ist oft schwierig, ein solches Speicherleck zu finden. Und das Aufrufen von env- & gt; DeleteLocalRef () jedes Mal, wenn Sie etwas mit JNI-lokalen Referenzen tun, überlagert nur den Code. Anstatt den Code mit DeleteLocalRef () Aufrufen zu überlisten, können wir einfach sicherstellen, dass wir nicht zu viele Referenzen erstellen und den Code sauber halten. Und selbst wenn wir viel mehr lokale Referenzen zuweisen möchten, können wir einfach PushLocalFrame () / PopLocalFrame () aufrufen und viele Aufrufe von DeleteLocalRef () vermeiden.
Um Ihnen eine Analogie zu "C" zu geben, werden Sie gebeten, Ihre Calls für malloc vorzuplanen, um alle notwendigen Aufrufe von free () am Ende zu vermeiden.
Die JNI-Dokumentation ist zu diesem Thema matschig. Ich habe in der Praxis festgestellt, dass die Anzahl der lokalen Referenzen manchmal unbegrenzt ist, aber Sie können wirklich keine lokalen Referenzen mehr haben, zum Beispiel beim Iterieren über ein Array mit JNI-Aufrufen. Was ist eine lokale Referenz? Es handelt sich um ein Job-Objekt (oder jarray, jstring usw.), das Sie aus einer dieser Quellen erhalten:
Davon müssen Sie sich in der Regel keine Gedanken über die Referenzen machen, die Ihnen in einem Methodenargument übergeben werden, AUSSER wenn Sie beabsichtigen, den Verweis über den aktuellen Methodenaufruf hinaus beizubehalten. In diesem Fall sollten Sie ihn in global konvertieren.
Es ist erwähnenswert, dass Sie sich nicht an eine lokale Referenz außerhalb des aktuellen Methodenbereichs halten müssen. Wenn Sie es in einem C ++ - Objekt speichern möchten, müssen Sie es in global konvertieren. Lokale Referenzen haben zwei Vorteile
Wie bei den meisten JNI-Fehlern ist jeder Missbrauch von Referenzen schrecklich zu diagnostizieren, also wollen Sie wirklich keinen bekommen. Ihre beste Verteidigung ist ein konsequenter Ansatz. Nach meiner Erfahrung sind die Kosten für die Umstellung von lokal auf global ziemlich gering. Ich würde folgendes vorschlagen, es sei denn, Sie haben sehr strenge Leistungsanforderungen.
In Anbetracht dessen lautet meine Regel: IMMER lokale Refs in globale Refs umwandeln, indem Code wie folgt verwendet wird:
An diesem Punkt können Sie wissen, dass jeder Verweis global ist, und wenn Sie fertig sind, müssen Sie daran denken, env- & gt; DeleteGlobalRef (globaljo) auf jedem zu machen. In C ++ ist es möglich, eine Wrapper-Klasse um JNI-Referenzen zu schreiben, die env- & gt; DeleteGlobalRef () im dtor aufruft. Da JNI jedoch nicht auf die JNI-Referenzen für Sie verweist, müssen Sie diese möglicherweise ebenfalls erstellen.