Быстрая стирание (непонятно) 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");