2008-12-03 5 views
22

Was ist der 'richtige' Weg, um einen nativen Zeiger in einem Java-Objekt zu speichern?Was ist der 'richtige' Weg, um einen nativen Zeiger in einem Java-Objekt zu speichern?

Ich konnte den Zeiger als Java int, behandeln, wenn ich, dass einheimische Zeiger weiß zufällig, < = 32 Bit groß sind, oder ein Java long wenn ich, dass einheimische Zeiger weiß zufällig, < = 64 Bit groß sind. Aber gibt es einen besseren oder saubereren Weg, dies zu tun?

bearbeiten: eine native Zeiger aus einer JNI-Funktion zurückkehrend ist genau das, was ich tun nicht wollen tun. Ich würde lieber ein Java-Objekt zurückgeben, das die native Ressource darstellt. Das von mir zurückgegebene Java-Objekt muss jedoch vermutlich ein Feld mit einem Zeiger enthalten, das mich zur ursprünglichen Frage zurückbringt.

Oder gibt es alternativ eine bessere Möglichkeit für eine JNI-Funktion, einen Verweis auf eine native Ressource zurückzugeben?

+0

eng mit der Frage im Zusammenhang http://stackoverflow.com/questions/1632367/passing-pointers-between-c-and-java-through-jni – Raedwald

Antwort

21

IIRC, beide java.util.zip und java.nio verwenden Sie einfach long.

+1

+1. Verwenden Sie eine lange, wie die Java-Laufzeit selbst tut. – erickson

+0

die Verwendung eines Objekts, das einen langen Wrapper hat, hat einen Overhead: Es könnte den Speicherverbrauch verdoppeln, da eine Objekt-Shell mindestens 8 Bytes belegen kann, ganz zu schweigen von den Instanzen Ihres Wrappertyps, die Garbage Collected sein müssen –

2

Eine bessere Möglichkeit könnte es in einem Byte-Array zu speichern, da native Zeiger in erster Linie nicht sehr Java-ish sind. int s und long s sind besser zum Speichern numerischer Werte reserviert.

2

Ich gehe davon aus, dass dies ein Zeiger von einem JNI-Code und mein Rat wäre es nur dont do :)

Idealerweise sollte die JNI Code Sie irgendeine Art von logischem Verweise übergibt zurück auf die Ressource zurückgegeben wird, und kein tatsächlicher Zeiger?

In Bezug auf Ihre Frage gibt es nichts, was in den Sinn kommt über eine sauberere Möglichkeit, den Zeiger zu speichern - wenn Sie wissen, was Sie haben dann verwenden Sie entweder die Int oder Long oder Byte [] wie erforderlich.

+0

Können Sie ein Beispiel einer ‚logischen Bezug auf die geben Ressource'? Ich habe meine Frage bearbeitet, um zu verdeutlichen, was ich eigentlich meinte. –

+0

Die logische Referenz wäre einfach eine Zahl, die der jni-Code zurückgibt, die bei nachfolgenden Aufrufen an die jni verwendet wird, um etwas zu referenzieren. Der jni-Code kann dann über eine Art von Struktur, z.B. ein Array [ref] [Zeiger]. hth – LenW

+1

Das würde bedeuten, ein Array zu verwalten, das Zeiger auf jede Ressource enthält, die von Java referenziert werden muss. Ich denke nicht, dass das eine sehr gute Idee ist ... –

0

Sie können nach der Art und Weise suchen, wie C# dies mit dem IntPtr-Typ behandelt. Wenn Sie einen eigenen Typ zum Halten von Zeigern erstellen, kann derselbe Typ je nach dem System, auf dem Sie sich befinden, als 32-Bit- oder 64-Bit-Typ verwendet werden.

3

Es gibt keinen guten Weg. In SWT wird dieser Code verwendet:

int /*long*/ hModule = OS.GetLibraryHandle(); 

und es ist ein Werkzeug, das den Code zwischen 32-Bit- und 64-Bit konvertiert durch den Kommentar zu bewegen. Hässlich, aber es funktioniert. Dinge wären viel einfacher gewesen, wenn Sun ein Objekt "NativePointer" oder etwas ähnliches hinzugefügt hätte, aber das taten sie nicht.

3

java.nio.DirectByteBuffer macht was Sie wollen.

Intern verwendet es einen private long address, um Zeigerwert zu speichern. Dah!

Verwenden Sie die JNI-Funktion env->NewDirectByteBuffer((void*) data, sizeof(MyNativeStruct)), um einen DirectByteBuffer auf der C/C++ - Seite zu erstellen und ihn als ByteBuffer an die Java-Seite zurückzugeben. Hinweis: Es ist Ihre Aufgabe, diese Daten auf der nativen Seite freizugeben! Es fehlt der automatische Cleaner, der auf dem Standard-DirectBuffer verfügbar ist.

Auf Java-Seite können Sie eine DirectByteBuffer auf diese Weise erstellen:

ByteBuffer directBuff = ByteBuffer.allocateDirect(sizeInBytes); 

malloc(sizeInBytes) es als eine Art C ist Denken. Hinweis: Es hat als automatische Cleaner, die den zuvor angeforderten Speicher freigibt.

Aber es gibt einige Punkte zu beachten, etwa DirectByteBuffer mit:

  • Es Müll gesammelt werden kann (GC), wenn Sie Ihren direkten ByteBuffer Bezug verpassen.
  • Sie können Werte in einer spitzen Struktur lesen/schreiben, aber achten Sie sowohl auf die Offset- als auch auf die Datengröße. Der Compiler kann zusätzliche Leerzeichen zum Auffüllen hinzufügen und die angenommenen internen Offsets in der Struktur unterbrechen. Struktur mit Zeigern (Schritt ist 4 oder 8 Bytes?) Auch Ihre Daten puzzle.
  • Direkte ByteBuffers sind sehr einfach als Parameter für native Methoden zu übergeben, auch um es als Rückgabe zurück zu erhalten.
  • Sie müssen eine Umwandlung durchführen, um den Zeigertyp auf der JNI-Seite zu korrigieren. Der von env->GetDirectBufferAddress(buffer) zurückgegebene Standardtyp ist void*.
  • Sie können den Zeigerwert nach der Erstellung nicht ändern.
  • Es ist Ihre Aufgabe, Speicher freizugeben, der zuvor für Puffer auf nativer Seite reserviert wurde. Diese haben Sie mit env->NewDirectByteBuffer() verwendet.
Verwandte Themen