Multimap Space Issue: Гуава - PullRequest
       35

Multimap Space Issue: Гуава

7 голосов
/ 29 марта 2012

В моем Java-коде я использую Multimap Guava ( com.google.common.collect.Multimap ), используя это:

 Multimap<Integer, Integer> Index = HashMultimap.create()

Здесь ключ Multimap - это некоторая частьURL и значение - это другая часть URL (преобразованная в целое число).Теперь я назначаю пространство кучи JVM 2560 МБ (2,5 ГБ) (используя Xmx и Xms).Тем не менее, он может хранить только 9 миллионов таких (ключ, значение) пар целых чисел (около 10 миллионов).Но теоретически (согласно памяти, занятой int) он должен хранить больше.

Кто-нибудь может мне помочь,

  1. Почему Multimap использует много памяти?Я проверил свой код и, не вставляя пары в Multimap, он использует только 1/2 МБ памяти.

Есть ли другой способ или решение для домашнего использования, чтобы решить эту проблему?проблема с памятью? Значит, есть ли способ уменьшить накладные расходы этих объектов, так как я хочу хранить только int-int?На каком-либо другом языке?Или любое другое решение (предпочтительное для домашней выпечки) для решения проблемы, с которой я столкнулся, - это решение на основе БД или что-то подобное.

Ответы [ 4 ]

9 голосов
/ 29 марта 2012

С Multimap связано огромное количество накладных расходов.Как минимум:

  • Каждый ключ и значение являются объектом Integer, который (как минимум) удваивает требования к хранилищу для каждого значения int.
  • Каждый уникальный ключзначение в HashMultimap связано с Collection значений (в соответствии с источником , Collection является Hashset).
  • Каждый Hashset созданс пространством по умолчанию для 8 значений.

Таким образом, каждой паре ключ / значение требуется (как минимум), возможно, на порядок больше места, чем можно было бы ожидать для двух значений int.(Несколько меньше, когда несколько значений хранятся под одним ключом.) Я ожидаю, что 10 миллионов пар ключ / значение займет, возможно, 400 МБ.

Хотя у вас есть 2,5 ГБ пространства кучи, я бы не стал этим заниматься.удивлен, если этого недостаточно.Приведенная выше оценка, я думаю, на низкой стороне.Кроме того, он учитывает только то, сколько необходимо для хранения карты после ее построения.По мере роста карты таблицу необходимо перераспределять и перефразировать, что временно по крайней мере удваивает объем используемого пространства.Наконец, все это предполагает, что int значения и ссылки на объекты требуют 4 байта.Если JVM использует 64-битную адресацию, число байтов, вероятно, удваивается.

4 голосов
/ 29 марта 2012

Вероятно, самый простой способ минимизировать накладные расходы памяти - это потенциально смешать реализации примитива Trove * (чтобы избежать накладных расходов памяти на упаковку) и Multimap в Guava, что-то вроде

SetMultimap<Integer, Integer> multimap = Multimaps.newSetMultimap(
  TDecorators.wrap(TIntObjectHashMap<Collection<Integer>>()),
  new Supplier<Set<Integer>>() {
    public Set<Integer> get() {
      return TDecorators.wrap(new TIntHashSet());
    }
  });

Это все еще накладывает издержки на упаковку и распаковку запросов, но память, которую он потребляет, просто сидя там, будет значительно уменьшена.

1 голос
/ 29 марта 2012

Похоже, вам нужна разреженная логическая матрица. Разреженные матрицы / массивы в Java должны обеспечивать указатели на код библиотеки. Затем вместо того, чтобы поместить (i, j) в мультикарту, просто поместите 1 в матрицу в [i] [j].

0 голосов
/ 13 апреля 2012

Возможно, вы могли бы использовать ArrayListMultimap, который требует меньше памяти, чем HashMultimap, поскольку ArrayLists меньше, чем HashSets. Или вы можете изменить решение Louis Trove, заменив Set на List, чтобы еще больше сократить использование памяти.

Некоторые приложения зависят от того факта, что HashMultimap удовлетворяет интерфейсу SetMultimap, но большинство - нет.

...