2012-06-25 22 views
10

Estoy tratando de "limpiar" un ByteBuffer para que sea cero bytes (todos 0x00). Traté de recorrer todas las posiciones en el búfer y configurarlas en 0x00, pero la eficiencia es mala. ¿Hay alguna forma mejor de borrar rápidamente un ByteBuffer, similar a lo que hace BitSet.clear()?Borrado rápido (no claro) un ByteBuffer en Java

Tenga en cuenta que ByteBuffer.clear() no es una solución adecuada para mí en este escenario: tengo que borrar todos los datos dentro del búfer, y no solo reiniciar el puntero al principio.

¿Alguna pista?

Editar: el ByteBuffer se utiliza como parte de la tabla hash, y mantiene las referencias de las entradas de la tabla hash. Cada vez que se necesita enjuagar la tabla hash, tengo que restablecer las entradas de la tabla hash para una posterior inserción de la tabla hash. Como se accede a la tabla hash de forma aleatoria, no puedo simplemente borrar() el estado del búfer de bytes.

+0

¿Puede explicar el caso de uso con más detalle? ¿De qué obtienes el bytebuffer? – jontro

+0

¿Por qué crees que necesitas poner a cero el búfer? – EJP

+0

¿Es un buffer directo? Si no, ¿qué pasa con 'ByteBuffer.wrap (nuevo byte [123456]);' –

Respuesta

6

¿Ha intentado utilizar uno de los métodos ByteBuffer.put(byte[]) o ByteBuffer.put(ByteBuffer) para escribir varios ceros de una vez? A continuación, puede iterar sobre el búfer en fragmentos de 100 u 1000 bytes, o lo que sea, usando una matriz o un búfer prellenado con ceros.

Desventaja: esta es una operación opcional, por lo que no se requieren todas las implementaciones de ByteBuffer que le proporcione ...

+0

Lo intentaré. Esperemos que una puesta en masa sea mejor que el ciclo ... ¡gracias! – asksw0rder

+2

Disculpe esta respuesta tardía, pero este enfoque realmente funciona para reducir la sobrecarga de descarga. He visto que el tiempo de descarga disminuyó de ~ 60 ms a ~ 2 ms. Veremos si es lo suficientemente bueno. – asksw0rder

4

Para ByteBuffer implementaciones que proporcionan la array() método opcional (donde hasArray() vuelve true), se podrían utilizar esta método obtener una referencia a la matriz subyacente, luego use java.util.Arrays#fill().

1

Si necesita un ByteBuffer lleno de cero reciente y limpio después de que la tabla hash se vacíe, la forma más fácil es olvidar el ByteBufefr existente y asignar uno nuevo. La documentación oficial no lo dice, pero todas las implementaciones conocidas ponen a cero la memoria de los nuevos almacenamientos intermedios. Consulte http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6535542 para obtener información adicional.

1

Como menciona DNA, tener un búfer precargado y usar ByteBuffer.put(ByteBuffer) es probablemente la forma portátil más rápida. Si eso no es práctico, se puede hacer algo como esto para aprovechar bien Arrays.fill o Unsafe.putLong cuando sea aplicable:

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); 
     } 
    } 
} 

Configuración UNALIGNED_ACCESS requiere cierto conocimiento de su aplicación JRE y la plataforma. Así es como lo configuraría para Oracle JRE cuando también utilice JNA (que proporciona Platform.ARCH como una manera práctica y canónica de acceder a la propiedad del 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"); 
Cuestiones relacionadas