2008-12-03 25 views
22

Jaki jest "poprawny" sposób przechowywania natywnego wskaźnika wewnątrz obiektu Java?Jaki jest "poprawny" sposób przechowywania natywnego wskaźnika wewnątrz obiektu Java?

mógłbym potraktować wskaźnik jako Java int, jeśli zdarzy się, że rodzime wskaźniki są < = 32 bity w rozmiarze lub Java long jeśli zdarzy się, że rodzime wskaźniki są < = 64 bity w rozmiarze. Ale czy istnieje lepszy lub czystszy sposób na zrobienie tego?

Edit: Wracając rodzimych wskaźnik z funkcji JNI jest dokładnie to, co ja nie chcesz zrobić. Wolałbym zwrócić obiekt Java, który reprezentuje rodzimy zasób. Jednak zwracany obiekt Java musi mieć pole zawierające wskaźnik, który prowadzi mnie z powrotem do pierwotnego pytania.

A może jest jakiś lepszy sposób, aby funkcja JNI zwracała odwołanie do natywnego zasobu?

+0

Ściśle związane z pytaniem http://stackoverflow.com/questions/1632367/passing-pointers-between-c-and-java-through-jni – Raedwald

Odpowiedz

21

IIRC, zarówno java.util.zip, jak i java.nio wystarczy użyć long.

+1

+1. Użyj długiego, ponieważ samo środowisko Java robi. – erickson

+0

użycie obiektu, który zawija długi ma narzut: może podwoić zużycie pamięci, ponieważ powłoka obiektu może zajmować co najmniej 8 bajtów, nie wspominając o tym, że wystąpienia typu opakowania muszą być zebrane jako śmieci –

2

Lepszym sposobem może być przechowywanie go w tablicy bajtów, ponieważ natywne wskaźniki nie są w dużej mierze Java-owskie. int s i long s są lepiej zarezerwowane do przechowywania wartości liczbowych.

2

Zakładam, że jest to wskaźnik wrócił z jakiegoś kodu JNI i moja rada byłaby prostu nie zrobić to :)

Idealnie kod JNI powinny przejść z powrotem jakiegoś logicznego odniesieniu do zasobu i nie jest prawdziwym wskaźnikiem?

Jeśli chodzi o twoje pytanie, nie ma nic, co przychodzi ci na myśl o czystszym sposobie przechowywania wskaźnika - jeśli wiesz, co masz, użyj odpowiednio int lub long lub byte [].

+0

może Pan podać przykład „logicznego odniesienia do ratunek'? Zmieniłem moje pytanie, aby wyjaśnić, co miałem na myśli. –

+0

Referencja logiczna byłaby po prostu liczbą zwracaną przez kod jni, która jest używana w wywołaniach subseowent z powrotem do jni, aby odwoływać się do czegoś. kod jni może następnie dereferencji, która za pośrednictwem jakiejś struktury, np. tablica [ref] [wskaźnik]. hth – LenW

+1

Oznaczałoby to utrzymanie tablicy zawierającej wskaźniki dla każdego zasobu, do którego należy odwoływać się z Javy. Nie sądzę, że to bardzo dobry pomysł ... –

0

Można spojrzeć w sposób, w jaki C# obsługuje to z typem IntPtr. Tworząc własny typ dla wskaźników trzymania, ten sam typ może być użyty jako 32-bitowy lub 64-bitowy, w zależności od systemu, w którym się znajdujesz.

3

Nie ma dobrej drogi. W SWT, ten kod jest używany:

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

a tam jest narzędzie, które konwertuje kod 32bit i 64bit między przesuwając komentarz. Brzydki, ale działa. Rzeczy byłoby o wiele łatwiej, gdyby Sun dodał obiekt "NativePointer" lub coś podobnego, ale tak się nie stało.

3

java.nio.DirectByteBuffer robi to, co chcesz.

Wewnętrznie używa private long address do przechowywania wartości wskaźnika. Dah!

Użyj funkcji JNI env->NewDirectByteBuffer((void*) data, sizeof(MyNativeStruct)), aby utworzyć stronę DirectByteBuffer po stronie C/C++ i przywrócić ją do strony Java jako ByteBuffer. Uwaga: Twoim zadaniem jest uwolnić te dane po stronie macierzystej! Brakuje automatycznego Cleanera dostępnego na standardowym DirectBuffer.

u boku Java, można utworzyć ten sposób DirectByteBuffer:

ByteBuffer directBuff = ByteBuffer.allocateDirect(sizeInBytes); 

myślę, że jako rodzaj C na malloc(sizeInBytes). Uwaga: Ma funkcję automatycznego czyszczenia, która zwalnia pamięć poprzednio żądaną.

Ale istnieje kilka punktów do rozważenia na temat korzystania DirectByteBuffer:

  • może być Śmieci zebrane (GC), jeśli stracisz bezpośredniego odniesienia ByteBuffer.
  • Możesz odczytywać i zapisywać wartości dla wskazanej struktury, ale uważaj zarówno na przesunięcie, jak i rozmiar danych. Kompilator może dodać dodatkowe spacje do wypełnienia i złamać założone wewnętrzne przesunięcia w strukturze. Struktura ze wskaźnikami (krok to 4 lub 8 bajtów?) Również łamie twoje dane.
  • Direct ByteBuffers są bardzo łatwe do przekazania jako parametr dla metod natywnych, a także do odzyskania jako powrót.
  • Musisz rzucić, aby poprawić typ wskaźnika po stronie JNI. Domyślny typ zwracany przez env->GetDirectBufferAddress(buffer) to void*.
  • Po utworzeniu nie można zmienić wartości wskaźnika.
  • Twoim zadaniem jest zwolnić pamięć poprzednio przypisaną do buforów po stronie natywnej. Te, których używałeś z env->NewDirectByteBuffer().
Powiązane problemy