HashMap альтернативы для хранения данных с эффективным использованием памяти - PullRequest
26 голосов
/ 19 октября 2010

В настоящее время у меня есть программа типа электронных таблиц, которая хранит свои данные в ArrayList HashMaps. Вы, несомненно, будете шокированы, когда я скажу вам, что это не оказалось идеальным. Похоже, что служебные данные используют в 5 раз больше памяти, чем сами данные.

Этот вопрос задает вопрос об эффективных библиотеках коллекций, и ответом было использование Google Collections. Мое наблюдение: " какая часть? " . Я читал документацию, но не думаю, что она дает очень хорошее представление о том, какие классы подходят для этого. (Я также открыт для других библиотек или предложений).

Так что я ищу что-то, что позволило бы мне хранить плотные данные типа электронных таблиц с минимальными перегрузками памяти.

  • На мои столбцы в настоящее время ссылаются объекты Field, строки на их индексы, а значения - это Objects, почти всегда Strings
  • В некоторых столбцах будет много повторяющихся значений
  • основными операциями являются обновление или удаление записей на основе значений определенных полей, а также добавление / удаление / объединение столбцов

Мне известны такие опции, как H2 и Derby, но в этом случае я не собираюсь использовать встроенную базу данных.

РЕДАКТИРОВАТЬ : Если вы предлагаете библиотеки, я также был бы признателен, если бы вы указали мне один или два класса в них, которые применимы здесь. Принимая во внимание, что документация Sun обычно включает информацию о том, какие операции являются O (1), которые являются O (N) и т. Д., Я не вижу большой части этого в сторонних библиотеках, и на самом деле никакого описания того, какие классы лучше всего подходят для каких .

Ответы [ 10 ]

11 голосов
/ 19 октября 2010

В некоторых столбцах будет много повторяющихся значений

немедленно предлагает мне возможное использование шаблона FlyWeight , независимо от того, какое решение вы выбрали для своегоколлекции.

5 голосов
/ 19 октября 2010

Коллекции Trove должны уделять особое внимание занимаемому пространству (я думаю, что они также имеют адаптированные структуры данных, если вы придерживаетесь примитивных типов) .. посмотрите здесь .

В противном случае вы можете попробовать коллекций Apache .. просто сделайте свои тесты!

В любом случае, если у вас много ссылок на одни и те же элементы, попробуйте разработать какой-нибудь подходящий шаблон(как вес в полете )

4 голосов
/ 20 октября 2010

Итак, я предполагаю, что у вас есть карта Map<ColumnName,Column>, где столбец на самом деле что-то вроде ArrayList<Object>.

Несколько возможностей -

  • Вы полностью уверены, что проблема с памятью? Если вы просто беспокоитесь о размере, стоит подтвердить, что это действительно проблема в работающей программе. Требуется очень много строк и карт, чтобы заполнить JVM.

  • Вы можете проверить свой набор данных с различными типами карт в коллекциях. В зависимости от ваших данных вы также можете инициализировать карты с помощью предварительно заданных комбинаций размера / коэффициента загрузки, которые могут помочь. В прошлом я облажался с этим, если вам повезет, вы можете получить на 30% меньше памяти.

  • Как насчет хранения ваших данных в единой матричной структуре данных (существующая реализация библиотеки или что-то вроде обертки вокруг списка списков) с единой картой, которая отображает ключи столбцов в столбцы матрицы?

3 голосов
/ 20 октября 2010

Предполагая, что все ваши строки имеют большинство одинаковых столбцов, вы можете просто использовать массив для каждой строки и Map для поиска, какие столбцы ссылаются на какую ячейку. Таким образом, у вас есть только 4-8 байтов служебной информации на ячейку.

Если строки часто повторяются, вы можете использовать пул строк, чтобы уменьшить дублирование строк. Пулы объектов для других неизменяемых типов могут быть полезны для сокращения потребляемой памяти.

РЕДАКТИРОВАТЬ: Вы можете структурировать данные как на основе строки или столбца. Если его строки основаны (один массив ячеек на строку), добавление / удаление строки - это просто вопрос удаления этой строки. Если его столбцы основаны, вы можете иметь массив для каждого столбца. Это может сделать обработку примитивных типов намного более эффективной. т. е. у вас может быть один столбец с типом int [], а другой с двойным [], гораздо чаще для всего столбца используется один и тот же тип данных, чем для одного и того же типа данных для всей строки.

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

(Что-то, что я делаю, это имею данные на основе строк и добавляю столбцы в конец, при условии, что если строка недостаточно длинна, столбец имеет значение по умолчанию, это позволяет избежать перестроения при добавлении столбца. Вместо удаления столбца , У меня есть способ игнорировать это)

2 голосов
/ 20 октября 2010

Guava включает в себя интерфейс Table и реализацию на основе хеша. Похоже, естественное соответствие вашей проблемы. Обратите внимание, что это все еще помечено как бета.

1 голос
/ 19 марта 2017

Карта хроники может иметь служебную нагрузку менее 20 байт на запись (см. тест , подтверждающий это).Для сравнения, издержки java.util.HashMap варьируются от 37-42 байтов с -XX:+UseCompressedOops до 58-69 байтов без сжатых операций ( ссылка ).

Кроме того, Chronicle Map хранит ключи изначения вне кучи, поэтому он не хранит заголовки объектов, которые не учитываются как издержки HashMap выше.Chronicle Map объединяет с Chronicle-Values ​​, библиотекой для генерации реализаций интерфейсов с упрощенным интерфейсом, шаблон , предложенный Брайаном Агнью в другом ответе.

1 голос
/ 29 октября 2010

Я экспериментировал с использованием SparseObjectMatrix2D из проекта Colt .Мои данные довольно плотные, но их классы Matrix на самом деле не предлагают никакого способа их увеличения, поэтому я использовал разреженную матрицу, настроенную на максимальный размер.примерно на 15% быстрее для тех же данных, а также предлагает некоторые умные методы манипуляции.Тем не менее, все еще заинтересованы в других вариантах.

1 голос
/ 20 октября 2010

хранит свои данные в ArrayList HashMaps
Ну, эта часть кажется мне ужасно неэффективной. Пустой HashMap уже выделит 16 * size of a pointer байтов (16 означает начальную емкость по умолчанию), а также некоторые переменные для хеш-объекта (14 + psize). Если у вас много незаполненных строк, это может быть большой проблемой.

Одним из вариантов будет использование одного большого хэша с составным ключом (объединение строки и столбца). Хотя это не делает операции над целыми строками очень эффективными.

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

Я не знаю много о коллекциях Google, поэтому не могу помочь. Также, если вы найдете какую-либо полезную оптимизацию, пожалуйста, пишите здесь! Было бы интересно узнать.

0 голосов
/ 21 июля 2012

Почему бы вам не попробовать использовать реализацию кеша, такую ​​как EHCache . Это оказалось очень эффективным для меня, когда я попал в ту же ситуацию.
Вы можете просто сохранить свою коллекцию в реализации EHcache. Есть конфигурации как:

Maximum bytes to be used from Local heap.

Как только байты, используемые вашим приложением, переполняются, настроенные в кеше, реализация кеша заботится о записи данных на диск. Также вы можете настроить время, по истечении которого объекты записываются на диск, используя алгоритм Least Recent Used. Вы можете быть уверены, что избежите ошибок нехватки памяти, используя этот тип реализаций кэша. Это лишь немного увеличивает операции ввода-вывода вашего приложения.
Это просто вид с высоты птичьего полета конфигурации. Существует множество конфигураций для оптимизации ваших требований.

0 голосов
/ 20 октября 2010

Из вашего описания кажется, что вместо ArrayList из HashMaps вы предпочитаете (связанный) HashMap из ArrayList (каждый ArrayList будет столбцом).

Я быдобавьте двойную карту от имени поля к номеру столбца и некоторые умные методы получения / установки, которые никогда не выбрасывают IndexOutOfBoundsException.

Вы также можете использовать ArrayList<ArrayList<Object>> (в основном, зубчатую динамически растущую матрицу) и сохранятьсопоставление с именами полей (столбцов) снаружи.

Некоторые столбцы будут иметь много повторяющихся значений

Я сомневаюсь, что это имеет значение, особенно если они являются строками (ониявляются внутренними), и ваша коллекция будет хранить ссылки на них.

...