Быстрая стирание (непонятно) ByteBuffer в Java

Я пытаюсь "очистить" ByteBuffer для всех нулевых байтов (все 0x00). Я попытался перебрать все позиции в буфере и установить их в 0x00, но эффективность плохая. Есть ли лучший способ быстро очистить ByteBuffer - похожее на то, что делает BitSet.clear()?

Обратите внимание, что ByteBuffer.clear() не подходит для меня в этом сценарии - мне нужно стереть все данные внутри буфера, а не только reset указатель на начало.

Любые подсказки?

Изменить: ByteBuffer используется как часть хеш-таблицы и поддерживает ссылки на записи хеш-таблицы. Каждый раз, когда хеш-таблицу нужно очищать, я должен reset записи хэш-таблицы для последующей вставки в хэш-таблицу. Поскольку хэш-таблица получает доступ случайно, я не могу просто очистить() состояние байтового буфера.

Ответ 1

Пробовали ли вы использовать один из методов ByteBuffer.put(byte[]) или ByteBuffer.put(ByteBuffer) для записи нескольких нулей за один раз? Затем вы можете перебирать буфер в кусках 100 или 1000 байт или что угодно, используя массив или буфер, предварительно заполненный нулями.

Нижняя сторона: это необязательная операция, поэтому не все реализации ByteBuffer необходимы для ее предоставления...

Ответ 2

Для ByteBuffer реализаций, которые предоставляют необязательный метод array() (где hasArray() возвращает true), вы можете использовать этот метод, чтобы получить ссылку на базовый массив, затем используйте java.util.Arrays#fill().

Ответ 3

Если вам понадобится свежий чистый заполненный нулем ByteBuffer после того, как хеш-таблица будет очищена, самый простой способ - забыть существующий ByteBufefr и выделить новый. Официальная документация не говорит об этом, но все известные реализации обнуляют память новых буферов. Подробнее см. http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6535542.

Ответ 4

Как упоминает ДНК, наличие предварительно заполненного буфера и использование ByteBuffer.put(ByteBuffer), вероятно, является самым быстрым переносным способом. Если это не практично, вы можете сделать что-то подобное, чтобы воспользоваться либо Arrays.fill, либо Unsafe.putLong, если применимо:

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

Настройка UNALIGNED_ACCESS требует определенных знаний о вашей реализации и платформе JRE. Здесь, как я бы установил его для Oracle JRE, когда также использовал JNA (который предоставляет Platform.ARCH как удобный, канонический способ доступа к системному свойству 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");