2012-06-25 16 views
10

Sto provando a "ripulire" uno ByteBuffer in modo che siano tutti a zero byte (tutti 0x00). Ho provato ad eseguire il loop su tutte le posizioni nel buffer e impostarle su 0x00, ma l'efficienza è negativa. C'è un modo migliore per cancellare rapidamente un ByteBuffer - simile a quello che fa BitSet.clear()?Cancellazione rapida (non chiara) a ByteBuffer in Java

Si prega di notare che ByteBuffer.clear() non è una soluzione appropriata per me in questo scenario - Devo cancellare tutti i dati all'interno del buffer, e non solo ripristinare il puntatore all'inizio.

Eventuali suggerimenti?

Modifica: il ByteBuffer viene utilizzato come parte della tabella hash e mantiene i riferimenti delle voci della tabella hash. Ogni volta che la tabella hash deve essere scaricata, devo reimpostare le voci della tabella hash per l'inserimento successivo della tabella hash. Poiché si accede alla tabella hash in modo casuale, non posso semplicemente cancellare() lo stato del buffer di byte.

+0

Puoi spiegare il caso d'uso in maggior dettaglio? Da cosa ottieni il bytebuffer? – jontro

+0

Perché pensi di dover azzerare il buffer? – EJP

+0

È un buffer diretto? In caso contrario, per quanto riguarda 'ByteBuffer.wrap (new byte [123456]);' –

risposta

6

Hai provato a utilizzare uno dei metodi ByteBuffer.put(byte[]) o ByteBuffer.put(ByteBuffer) per scrivere più zeri in una volta? È quindi possibile eseguire iterazioni sul buffer in blocchi di 100 o 1000 byte, o qualsiasi altra cosa, utilizzando un array o un buffer pre-riempito di zeri.

Lato negativo: si tratta di un'operazione facoltativa, quindi non tutte le implementazioni di ByteBuffer sono tenuti a fornire ...

+0

Ci proveremo. Speriamo che un grosso carico sia migliore del ciclo ... grazie! – asksw0rder

+2

Ci scusiamo per questa risposta tardiva, ma questo approccio funziona davvero per ridurre il sovraccarico di flushing. Ho visto diminuire il tempo di lavaggio da ~ 60ms a ~ 2ms. Vedremo se è abbastanza buono. – asksw0rder

4

Per ByteBuffer implementazioni che forniscono il array() metodo facoltativo (dove hasArray() rendimenti true), si potrebbe utilizzare questo metodo ottenere un riferimento alla matrice sottostante, quindi utilizzare java.util.Arrays#fill().

1

Se è necessario un ByteBuffer pulito a zero pulito dopo che la tabella hash è stata scaricata, il modo più semplice è quello di dimenticare il ByteBufefr esistente e assegnarne uno nuovo. La documentazione ufficiale non lo dice, ma tutte le implementazioni conosciute azzerano la memoria dei nuovi buffer. Vedi http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6535542 per ulteriori informazioni.

1

Come indica il DNA, avere un buffer pre-riempito e usare ByteBuffer.put(ByteBuffer) è probabilmente il modo più veloce portatile. Se questo non è pratico, si può fare qualcosa di simile per sfruttare sia Arrays.fill o Unsafe.putLong quando applicabile:

public static void fill(ByteBuffer buf, byte b) { 
    if (buf.hasArray()) { 
     final int offset = buf.arrayOffset(); 
     Arrays.fill(buf.array(), offset + buf.position(), offset + buf.limit(), b); 
     buf.position(buf.limit()); 
    } else { 
     int remaining = buf.remaining(); 
     if (UNALIGNED_ACCESS) { 
      final int i = (b << 24) | (b << 16) | (b << 8) | b; 
      final long l = ((long) i << 32) | i; 
      while (remaining >= 8) { 
       buf.putLong(l); 
       remaining -= 8; 
      } 
     } 
     while (remaining-- > 0) { 
      buf.put(b); 
     } 
    } 
} 

Impostazione UNALIGNED_ACCESS richiede una certa conoscenza della vostra implementazione JRE e la piattaforma. Ecco come impostarlo per Oracle JRE quando si utilizza anche JNA (che fornisce Platform.ARCH come un modo comodo e canonico per accedere alla proprietà di sistema os.arch).

/** 
* Indicates whether the ByteBuffer implementation likely supports unaligned 
* access of multi-byte values on the current platform. 
*/ 
private static final boolean UNALIGNED_ACCESS = Platform.ARCH.startsWith("x86");