Создание кеша байтовых массивов - программирование
Подтвердить что ты не робот

Создание кеша байтовых массивов

В моем коде, который часто работает на серверах, я не контролирую конфигурацию, у меня есть коллекция пользователей, и каждый пользователь имеет массив byte[].

Иногда эти массивы byte[] уникальны для пользователя. Часто, однако, будут пользователи с большим количеством чисел с точно таким же массивом byte[].

Я пытаюсь уменьшить потребление ОЗУ моего сервера.

Я попытался превратить массивы byte[] в строки и интернировать их, но затем я часто сталкиваюсь с ошибками памяти PERM-GEN. Я также вижу значительное ухудшение производительности при кодировании/декодировании, когда я хочу получить доступ к массиву byte[] для пользователя, и я вижу значительно увеличенное использование памяти в худшем случае. Существующая строка намного больше, чем массивы.

Как я могу найти поиск Set<SoftReference<byte[]>>, когда массивы Java не являются хешируемыми, а SoftReferences не переносят хэш объекта в точку. A Map<byte[],SoftReference<byte[]>>, очевидно, также побеждает себя, потому что ключ сам по себе и предотвращает сбор; и Set в любом случае реализуется внутри Map.

Итак, как я могу ставить byte[] массивы?

4b9b3361

Ответ 1

Если у вас есть много одинаковых массивов, используйте HashSet<ByteBuffer> в качестве кеша. Вы можете получить массив ByteBuffer с помощью метода array(), а класс ByteBuffer имеет методы hashCode и equals. Конечно, лучше, если ваши массивы неизменны.

EDIT2 Комментарий от @Will является точным, чтобы иметь возможность вернуть массив, использовать WeakHashMap<ByteBuffer,WeakReference<ByteBuffer>> и сделать что-то вроде этого:

public byte[] internalize(byte[] bytes) {
 ByteBuffer wrapped = ByteBuffer.wrap(bytes);
 if(cache.containsKey(wrapped)) {
  wrapped = cache.get(wrapped).get();
 }
 else {
  cache.put(wrapped, new WeakReference<ByteBuffer>(wrapped);
 }
 return wrapped.array();
}

Ответ 2

Я попытался превратить массивы байтов [] в строки и интернировать их, но затем я часто сталкиваюсь с ошибками памяти PERM-GEN.

Я согласен, что вам нужно что-то вроде String.intern(), но стандартная реализация native, поэтому не так много радости.

У вас может быть Map<Integer,Collection<SoftReference<byte[]>>>, используя хэш-код массивов байтов в качестве клавиши Map. Затем ваш метод intern мог бы искать набор существующих массивов байтов с тем же кодом, что и заданные байтовые массивы. С хорошим хеш-кодом, который должен дать небольшой набор массивов для проверки на соответствие.


Изменить: уточнить:

Что-то вроде этого:

 class ByteArrayCache
 {
      private final Map<Integer,Collection<SoftReference<byte[]>> map = new ...;

      public final byte[] intern(byte[] byteArray)
      {
           final int hash = Arrays.hashCode(byteArray);
           final Collection<SoftReference<byte[]>> arrays = map.get(hash);
           if (arrays != null) {
              // Search through arrays for a match, and return the match.
              // If no match found, add byteArray to the collection and return it
           } else {
              // create a new map entry, add byteArray to it, and return byte array
           }
      }
 }

Ответ 3

Я бы использовал кеш, основанный на карте слабых значений Guava. Это гарантирует, что если у вас нет более сильных ссылок на массив байтов, запись будет автоматически удалена.

class Cache {
    private final ConcurrentMap<Key, byte[]> map = new MapMaker().weakValues().makeMap();

    private static class Key {
        byte[] a;
        int hash;

        Key(byte[] a) {
            this.a = a;
            hash = Arrays.hashCode(a);
        }

        @Override
        public int hashCode() {
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj instanceof Key) {
                return Arrays.equals(a, ((Key) obj).a);
            }
            return false;
        }
    }

    public byte[] intern(byte[] a) {
        byte[] a1 = map.putIfAbsent(new Key(a), a);
        if (a1 != null) {
            return a1; 
        }
        return a;
    }
}