Pytanie 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?

Mogę traktować wskaźnik jako Java int, jeśli zdaję sobie sprawę, że rodzime wskaźniki mają <= 32 bity lub Java long jeśli zdaję sobie sprawę, że rodzime wskaźniki mają rozmiar <= 64 bity. Ale czy istnieje lepszy lub czystszy sposób na zrobienie tego?

Edytować: Zwrócenie natywnego wskaźnika z funkcji JNI jest dokładnie tym, co ja nie rób tego chcę 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.

Lub alternatywnie, istnieje jakiś lepszy sposób, aby funkcja JNI zwróciła odwołanie do natywnego zasobu?


23
2017-12-03 14:24


pochodzenie


Ściśle związane z pytaniem stackoverflow.com/questions/1632367/... - Raedwald


Odpowiedzi:


IIRC, oba java.util.zip i java.nio po prostu użyj long.


22
2017-12-03 14:47



+1. Użyj długiego, ponieważ samo środowisko Java robi. - erickson
używanie 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 otoki będą musiały zostać zebrane - Gregory Pakosz


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

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

i jest narzędzie, które konwertuje kod pomiędzy 32bit i 64bit, 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
2017-12-03 14:49





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ć DirectByteBuffer po stronie C / C ++ i powrócić do strony Java jako ByteBuffer. Uwaga: Twoim zadaniem jest uwolnić te dane po stronie natywnej! Brakuje automatycznego Cleanera dostępnego na standardowym DirectBuffer.

Po stronie Java możesz utworzyć DirectByteBuffer w ten sposób:

ByteBuffer directBuff = ByteBuffer.allocateDirect(sizeInBytes);

Pomyśl o tym jak o C malloc(sizeInBytes). Uwaga: Ma funkcję automatycznego czyszczenia, która zwalnia pamięć poprzednio żądaną.

Ale jest kilka rzeczy do rozważenia na temat korzystania z DirectByteBuffer:

  • Może to być Garbage Collected (GC), jeśli przegapisz bezpośrednie odniesienie do ByteBuffer.
  • Możesz odczytywać i zapisywać wartości do spiczastej 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 powrotu.
  • Musisz rzucić, aby poprawić typ wskaźnika po stronie JNI. Domyślny typ zwracany przez env->GetDirectBufferAddress(buffer) jest void*.
  • Po utworzeniu nie można zmienić wartości wskaźnika.
  • Twoim zadaniem jest zwolnić pamięć poprzednio przydzieloną dla buforów po stronie natywnej. Te, z którymi korzystałeś env->NewDirectByteBuffer().

3
2018-03-21 02:18





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


2
2017-12-03 14:32





Zakładam, że jest to wskaźnik zwrócony z jakiegoś kodu JNI i moja rada byłaby po prostu tego nie rób :)

Idealnie kod JNI powinien przekazać ci jakieś logiczne odwołanie do zasobu, a nie rzeczywisty wskaźnik?

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 [].


2
2017-12-03 14:32



Czy mógłbyś podać przykład "logicznego odniesienia do zasobu"? Zmieniłem moje pytanie, aby wyjaśnić, co miałem na myśli. - Daniel Cassidy
Referencja logiczna byłaby po prostu liczbą, którą zwraca kod jni, który jest używany w wywołaniach subseowentnych 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]. h - LenW
Oznaczałoby to utrzymanie tablicy zawierającej wskaźniki do każdego zasobu, do którego należy odwoływać się z Javy. Nie sądzę, że to bardzo dobry pomysł ... - Daniel Cassidy
To jest coś, co robi JVM. Widzę pewne zalety, że kod Java nie musi zajmować się specyfiką wskaźników w kodzie JNI i jest chroniony przed nimi. Ile zasobów udostępniasz z powrotem do kodu Java? Tablica 10000 elementów nie wydaje się zbyt duża :) - LenW
W praktyce prawdopodobnie mało. Ale po prostu nie podoba mi się pomysł narzucenia arbitralnego ograniczenia na tworzenie obiektów lub pisania kodu w celu zmiany wielkości tablic itp., Między innymi dlatego, że jest to kolejne źródło potencjalnych błędów. - Daniel Cassidy


Możesz patrzeć w sposób, w jaki C # radzi sobie z tym 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.


0
2017-12-03 14:41