2011-10-28 12 views
6

Staram się zrozumieć dokumentację sun.misc.Unsafe - jak sądzę, ponieważ nie jest ona przeznaczona do ogólnego użytku, nikt naprawdę nie zadał sobie trudu, żeby ją odczytać - ale naprawdę potrzebuję sposobu na znalezienie adresu element w tablicy (tak, że mogę przekazać do niego wskaźnik na kod natywny). Czy ktoś ma działający kod, który to robi? Czy to jest niezawodne?Użycie adresu sun.misc.Unsafe w celu uzyskania adresu elementów tablicy Java?

+0

http://stackoverflow.com/questions/5574241/interesting-uses-of-sun-misc-unsafe –

+0

[Dlaczego deweloperzy nie powinni pisać programów To wywołaj pakiety "słońce"] (http://www.oracle .com/technetwork/java/faq-sun-packages-142232.html) – BalusC

+0

imo, niebezpieczny dokument jest całkiem niezły, nie jest przeznaczony dla ogółu społeczeństwa. jeśli potrzebujesz pewnych wskazówek, zacznij czytać java.util.concurrent i java.util.concurrent.atomic ... niebezpieczne jest całkiem blisko C (lub asemblera, jeśli wolisz). Jeśli nie masz żadnego doświadczenia, jeśli nie, niebezpieczne nie jest dla ciebie. Jak zdemontować kod Java: http://wikis.sun.com/display/HotSpotInternals/PrintAssembly – bestsss

Odpowiedz

6

Zamiast korzystać z tablicy można użyć bezpośredniego bufora ByteBuffer.allocateDirect(). Ma on adres w polu i adres ten nie zmienia się przez cały okres istnienia Bajtowego Buźka. Bezpośredni ByteBuffer wykorzystuje minimalną przestrzeń sterty. Możesz uzyskać adres za pomocą refleksji.


Możesz użyć Unsafe, aby uzyskać adres, problem polega na tym, że GC może go przenieść w dowolnym momencie. Obiekty nie są naprawiane w pamięci.

W JNI można użyć specjalnych metod do kopiowania danych do/z obiektów Java, aby uniknąć tego problemu (i innych) Proponuję użyć ich, jeśli chcesz wymieniać dane między obiektami z kodem C.

+1

Wolałbym nie używać bezpośredniego bufora bajtowego (co raczej ułatwiłoby rozwiązywanie problemu), ponieważ utknąłem próbując zaimplementować istniejący interfejs API, który jest zdefiniowany w kategoriach tablic bajtowych, i próbuję uniknąć kary kopiowania do i z dodatkowego zestawu buforów. To wystarczy jako ostateczność, ale musi istnieć jakiś lepszy sposób. Praca z JNI ułatwiłaby to, ale niestety pracuję z JNA, która nie ma interfejsów niezbędnych do zrobienia czegoś innego niż praca z całymi tablicami. – Jules

+0

@ Jules, JNI spowoduje kopię samodzielnie, chyba że chcesz iść w/"GetPrimitiveArrayCritical", które mogą zranić GC. Ugryź punktor i skopiuj do pamięci bezpośredniej (bufor). To jedyne możliwe rozwiązanie. Na przykład impl. FileOutputStream (SocketOutputStream rozszerza go) używa kopii elementów na stosie. Kara za kopiowanie nie jest tak wysoka, ponieważ najwyższy koszt pochodzi z kosztu ładowania danych (i nawet z pamięci podręcznej), które musiałbyś zapłacić w dowolny sposób. Kopiowanie spowoduje również wstępne pobranie cachelines, więc może być jeszcze lepiej odrzucić sposób działania natywnego kodu. – bestsss

+0

@Jules, na marginesie: nawet javax.net.ssl.SSLEngine pozwala na użycie buforów, wszystkie algorytmy są bajtowe [] i kończą kopiowanie bezpośrednich buforów do tymczasowych tablic, jest to odwrotna historia i morał tego : nie używaj bezpośrednich buforów w/SSLEngine. – bestsss

6

Oto działająca próbka. Należy jednak zachować ostrożność, ponieważ może to łatwo spowodować awarię maszyny JVM przy niewłaściwym użytkowaniu klasy Unsafe.

import java.lang.reflect.Field; 

import sun.misc.Unsafe; 

public class UnsafeTest { 

    public static void main(String... args) { 
     Unsafe unsafe = null; 

     try { 
      Field field = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); 
      field.setAccessible(true); 
      unsafe = (sun.misc.Unsafe) field.get(null); 
     } catch (Exception e) { 
      throw new AssertionError(e); 
     } 

     int ten = 10; 
     byte size = 1; 
     long mem = unsafe.allocateMemory(size); 
     unsafe.putAddress(mem, ten); 
     long readValue = unsafe.getAddress(mem); 
     System.out.println("Val: " + readValue); 

    } 
} 
+2

Ten kod musi być całkowicie bezpieczny, ponieważ dokładnie działa DirectByteBuffer. Niestety nie robi tego, co chcę, czyli dostępu do danych w istniejącej macierzy. – Jules

+4

@StephenC, kod jest całkowicie w porządku, to w zasadzie 'char * mem = malloc (rozmiar); ...' nigdy nie jest dotykany przez GC i powoduje natywny wyciek C, chyba że zostanie wyrealizowany. – bestsss

+2

Kod jest w porządku, ale należy również rozważyć zwolnienie przydzielonej pamięci. Zobacz DirectByteBuffer dla jednego sposobu robienia tego. Weź również pod uwagę, że przydzielona pamięć nie jest wyzerowana, więc nie można założyć, że twoja bezpośrednia tablica jest zerowana. –

1

Dlaczego? W JNI dostępnych jest wiele narzędzi do radzenia sobie z zawartością tablic Java. Nie musisz korzystać z nieudokumentowanych wewnętrznych klas Sun, których może nie być w przyszłym tygodniu.

+0

Używam JNA, a nie JNI, a funkcja, z którą się łączę, musi mieć wskaźnik przekazany do środka tablicy, podczas gdy JNA wydaje się być w stanie wytworzyć wskaźnik na początku tablicy. – Jules

+0

@Jules, nie mieszaj JNA i normalnych tablic, używaj bezpośrednich buforów. – bestsss

Powiązane problemy