Sto faticando a capire la documentazione di sun.misc.Unsafe - Immagino che non è inteso per uso generale, nessuno si preoccupa davvero di renderlo leggibile - ma in realtà ho davvero bisogno di un modo per trovare l'indirizzo di un elemento in un array (in modo che io possa passare un puntatore ad esso al codice nativo). Qualcuno ha qualche codice funzionante che faccia questo? È affidabile?Utilizzo di sun.misc.Unsafe per ottenere l'indirizzo degli elementi dell'array Java?
risposta
Invece di utilizzare un array è possibile utilizzare un ByteBuffer.allocateDirect() tampone diretta. Questo ha l'indirizzo in un campo e questo indirizzo non cambia per la durata del ByteBuffer. ByteBuffer diretto utilizza uno spazio heap minimo. È possibile ottenere l'indirizzo utilizzando la riflessione.
È possibile utilizzare Unsafe per ottenere un indirizzo, il problema è che il GC può spostarlo in qualsiasi momento. Gli oggetti non sono riparati in memoria.
In JNI è possibile utilizzare metodi speciali per copiare dati da/per oggetti Java per evitare questo problema (e altri) Suggerisco di utilizzarli se si desidera scambiare dati tra oggetti con codice C.
Preferirei non utilizzare un buffer di byte diretto (che renderebbe la soluzione del problema piuttosto facile) poiché sono bloccato cercando di implementare un'API esistente definita in termini di matrici di byte e sto cercando di evitare la penalità della copia in e da un set aggiuntivo di buffer. Questo sarebbe sufficiente come ultima risorsa, ma deve esserci un modo migliore. Lavorare con JNI renderebbe tutto più semplice, ma sfortunatamente sto lavorando con JNA, che non sembra avere le interfacce necessarie per fare altro che lavorare con interi array. – Jules
@Jules, JNI genererà una copia autonomamente, a meno che non si desideri utilizzare w/'GetPrimitiveArrayCritical' che potrebbe danneggiare il GC. Mordere il proiettile e copiare nella memoria diretta (buffer). Questa è l'unica soluzione fattibile. Ad esempio l'impl. FileOutputStream (SocketOutputStream lo estende) utilizza la copia degli elementi nello stack. La penalità da copiare non è così alta, dal momento che il costo più alto viene fornito con il costo di caricamento dei dati (e anche i caching mancati) che dovresti pagare in entrambi i casi. La copia causerà anche il precaricamento delle linee di caching, quindi potrebbe essere ancora meglio la modalità di funzionamento del codice nativo. – bestsss
@Jules, su una nota a margine: anche javax.net.ssl.SSLEngine consente l'uso di buffer, tutti gli algoritmi sono byte [] e finiscono per copiare i buffer diretti in array temporanei, questa è la storia inversa e la morale di esso : non utilizzare buffer diretti con SSLEngine. – bestsss
Ecco un esempio funzionante. Si prega di fare attenzione, tuttavia, poiché si potrebbe facilmente bloccare la JVM con un uso inappropriato della classe 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);
}
}
Questo codice deve essere perfettamente sicuro, in quanto è esattamente come funziona DirectByteBuffer. Sfortunatamente, non fa quello che voglio, ovvero accedere ai dati in un array esistente. – Jules
@StephenC, il codice è perfettamente a posto, è fondamentalmente 'char * mem = malloc (dimensione); ...' non viene mai toccato dal GC e causa la perdita C nativa a meno che non venga eseguita. – bestsss
Il codice va bene, ma è anche necessario considerare di liberare la memoria allocata. Vedi DirectByteBuffer per un modo di farlo. Considerare anche che la memoria allocata non è azzerata, quindi non si può supporre che la matrice diretta sia inizializzata a zero. –
Perché? Ci sono molte strutture in JNI per trattare i contenuti degli array Java. Non è necessario utilizzare classi Sun interne non documentate che potrebbero non esserci la prossima settimana.
Sto usando JNA, piuttosto che JNI, e la funzione con cui sto interagendo deve avere un puntatore passato al centro di un array, mentre JNA sembra essere in grado di produrre un puntatore all'inizio di un array. – Jules
@Jules, non mescolare JNA e array normali, utilizzare buffer diretti. – bestsss
http://stackoverflow.com/questions/5574241/interesting-uses-of-sun-misc-unsafe –
[Perché gli sviluppatori non devono scrivere programmi That Call "sun" Packages] (http://www.oracle .com/technetwork/java/faq-sun-packages-142232.html) – BalusC
imo, doc non sicuro è abbastanza buono, non è destinato al pubblico in generale. se hai bisogno di alcune linee guida, inizia a leggere java.util.concurrent e java.util.concurrent.atomic ... non sicuro è abbastanza vicino a C (o assemblatore, se preferisci). Se non hai esperienza se ce ne sono, non è sicuro per te. Come ottenere il disassemblaggio del tuo codice java: http://wikis.sun.com/display/HotSpotInternals/PrintAssembly – bestsss