Domanda

Il mio obiettivo è garantire che un array allocato in java sia allocato nella memoria fisica contigua. Il problema che ho riscontrato è che le pagine su cui è allocato un array tendono a non essere contigue nella memoria fisica, a meno che non alloca un array molto grande.

Le mie domande sono:

  • Perché garantisce un array davvero grande pagine contigue nella memoria fisica?
  • Esiste un modo per garantire che un array sia allocato nella memoria fisica, ciò non implica che l'array sia veramente grande?
  • Come posso sapere in quale pagina o indirizzo fisico esiste un oggetto / array Java, senza misurare i risultati della cache / mancati cache?

Non cerco risposte che chiedano perché lo sto facendo in Java. Capisco che C "risolverà il mio problema" e che sto andando contro la natura fondamentale di Java. Tuttavia ho una buona ragione per farlo.

Non è necessario garantire che le risposte funzionino sempre. Sto cercando risposte che funzionino la maggior parte del tempo. Punti extra per risposte creative e immediate che nessun programmatore Java ragionevole avrebbe mai scritto. Va bene essere specifici della piattaforma (x86 32-bit 64-bit).

È stato utile?

Soluzione

Dato che il Garbage Collector sposta gli oggetti nella memoria (logica), penso che sarai sfortunato.

Il meglio che potresti fare è usare ByteBuffer.allocateDirect . Ciò (in genere) non verrà spostato nella memoria (logica) dal GC, ma potrebbe essere spostato nella memoria fisica o addirittura trasferito su disco. Se desideri garanzie migliori, dovrai colpire il sistema operativo.

Detto questo, se puoi impostare la dimensione della pagina in modo che sia grande come il tuo heap, allora tutti gli array saranno necessariamente contigui fisicamente (o scambiati).

Altri suggerimenti

No. La memoria fisicamente contigua richiede l'interazione diretta con il sistema operativo. La maggior parte delle applicazioni, inclusa JVM, ottiene solo indirizzi praticamente contigui. E una JVM non può darti ciò che non ottiene dal sistema operativo.

Inoltre, perché lo vorresti? Se stai impostando i trasferimenti DMA, probabilmente stai utilizzando tecniche diverse da Java.

Bit di sfondo:

La memoria fisica in un PC moderno è in genere una quantità flessibile, su moduli DIMM sostituibili. Ogni byte ha un indirizzo fisico, quindi il sistema operativo durante l'avvio determina quali indirizzi fisici sono disponibili. Si scopre che le applicazioni sono meglio non usando questi indirizzi direttamente. Al contrario, tutte le CPU moderne (e le relative cache) utilizzano indirizzi virtuali. Esiste una tabella di mappatura su indirizzi fisici, ma ciò non deve essere completo: lo scambio su disco è abilitato dall'uso di indirizzi virtuali non mappati su indirizzi fisici. Un altro livello di flessibilità si ottiene dall'avere una tabella per processo, con mappature incomplete. Se il processo A ha un indirizzo virtuale mappato sull'indirizzo fisico X, ma il processo B no, allora non c'è modo che il processo B possa scrivere sull'indirizzo fisico X e possiamo considerare che la memoria sia esclusiva per il processo A. Ovviamente affinché ciò sia sicuro, il sistema operativo deve proteggere l'accesso alla tabella di mappatura, ma tutti i sistemi operativi moderni lo fanno.

La tabella di mapping funziona a livello di pagina. Una pagina o un sottoinsieme contiguo di indirizzi fisici viene associato a un sottoinsieme contiguo di indirizzi virtuali. Il compromesso tra sovraccarico e granularità ha fatto sì che le pagine 4KB abbiano una dimensione di pagina comune. Ma poiché ogni pagina ha una propria mappatura, non si può assumere contiguità oltre quella dimensione di pagina. In particolare, quando le pagine vengono espulse dalla memoria fisica, scambiate su disco e ripristinate, è del tutto possibile che finisca in un nuovo indirizzo di memoria fisica. Il programma non nota, poiché l'indirizzo virtuale non cambia, solo la tabella di mappatura gestita dal sistema operativo.

Penso che vorresti usare sun.java. non sicuri.

Ci possono essere modi per ingannare una JVM specifica nel fare ciò che vuoi, ma probabilmente questi sarebbero fragili, complicati e molto probabilmente molto specifici per la JVM, la sua versione, il sistema operativo su cui gira ecc. In altre parole, uno sforzo sprecato .

Quindi, senza sapere di più sul tuo problema, non credo che nessuno sarà in grado di aiutarti. Non c'è sicuramente modo di farlo in Java in generale, al massimo su una JVM specifica.

Per suggerire un'alternativa:

Se hai davvero bisogno di archiviare i dati nella memoria contigua, perché non farlo in una piccola libreria C e chiamarla tramite JNI?

Come la vedo io. Devi ancora spiegare perché

  • che le matrici primitive non sono continue nella memoria. Non vedo perché non sarebbero continui nella memoria virtuale. (c.f. È improbabile che le matrici di oggetti abbiano i suoi oggetti continui in memoria)
  • un array che non è continuo nella memoria fisica (RAM, ad esempio la memoria ad accesso casuale) avrebbe una differenza di prestazioni significativa. per esempio. differenza misurabile nelle prestazioni della tua applicazione.

Ciò che sembra è che stai davvero cercando un modo di basso livello per allocare array perché sei abituato a farlo in C, e le prestazioni sono una rivendicazione per la necessità di farlo.

A proposito: l'accesso a ByteBuffer.allocateDirect () con getDouble () / putDouble () può essere più lento del fatto che l'utilizzo di un doppio [] poiché il primo comporta chiamate JNI e il secondo può essere ottimizzato per non chiamare affatto.

Il motivo per cui viene utilizzato è lo scambio di dati tra gli spazi Java e C. per esempio. Chiamate NIO. Funziona bene solo quando le operazioni di lettura / scrittura sono ridotte al minimo. Altrimenti stai meglio usando qualcosa nello spazio Java.

vale a dire. A meno che tu non sia chiaro ciò che stai facendo e perché lo stai facendo, puoi trovare una soluzione che potrebbe farti sentire meglio, ma in realtà è più complicato e funziona peggio della semplice soluzione.

Nota questa risposta a una domanda correlata, che tratta System.identityHashCode () e identificazione dell'indirizzo di memoria dell'oggetto. La linea di fondo è che è possibile utilizzare l'implementazione hashCode () predefinita dell'array per identificare l'indirizzo di memoria originale dell'array (soggetto a adattamento in un int / 32-bit)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top