Каковы издержки использования java.util.List для одного списка элементов? - PullRequest
0 голосов
/ 19 ноября 2018

У меня есть хранилище значений ключей в памяти (вероятно, до 1 ГБ), где отображается String на String.Пока что он реализован как Map<String, String>.

Однако есть редкий случай, когда мне нужно сопоставить список строк, поэтому мне нужно изменить это значение на Map<String, List<String>>.

Поскольку это не обычный случай (вероятно, менее чем% 1), я спорю, можно ли разделить эти сценарии использования на две разные карты.

Кто-нибудь знает, какие накладные расходы (объем памяти)и процессор) Я должен ожидать, что все списки на карте только с одним элементом, против непосредственно String объектов?

Спасибо!

Ответы [ 2 ]

0 голосов
/ 19 ноября 2018

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

В дополнение к предложениям Joop я могу представить несколько разных подходов:

  • Используйте прямое Map<String, List<String>>, используя ArrayList или аналогичный список общего назначения, тогда вы получите один дополнительный (довольно толстый) объект-оболочку, включая строковый массив (возможно, 128 байт) на каждую запись карты. Реализация из коробки, но тратит много памяти.

  • Используйте Map<String, List<String>> и убедитесь, что заключены однострочные значения в Collections.singletonList() или аналогичную компактную конструкцию. Затем вы получаете один дополнительный объект-обертку (от 16 до 32 байт) на одну строку. Меньшие накладные расходы, но требующие особой обработки при вставке одиночных строк.

  • Используйте две карты, одну Map<String, String> для одиночных строк и одну Map<String, List<String>> для многострочного регистра. Практически не требует дополнительных затрат, но требует особой обработки как при вставке записей, так и при запросах / итерации карты.

  • Решение каскадных строк в Joop объединяет два или более String экземпляров в один более длинный String, тем самым устраняя их отдельные накладные расходы. Это даже приводит к «отрицательным» накладным расходам, но требует особой обработки как при вставке записей, так и при запросе / повторении карты. Разделение String потребует чуть-чуть дополнительного времени выполнения при извлечении записей, даже для случая с одной строкой. [Хотя String.split() основан на регулярных выражениях, которые в общем случае очень медленные, решение Joop соответствует «быстрому пути» в реализации String.split() - спасибо Joop!]

Теперь выбор за вами.

0 голосов
/ 19 ноября 2018

Возможности (в порядке увеличения отпечатка памяти):

Map<String, String> map = new HashMap<>(); // Concatenated string values
List<String> get(String key) {
    return Arrays.asList(map.getOrDefault(key, "").split("\f"));
}

Map<String, String[]> map = new HashMap<>();
private static final String[] EMPTY = new String[0];
List<String> get(String key) {
    return Arrays.asList(map.getOrDefault(key, EMPTY));
}

Map<String, List<String>> map = new HashMap<>(); // LinkedList
List<String> get(String key) {
    return map.get(key);
}

(Просто пример кода. Я плохо справлялся с пустыми строками.)

Как говорили другие, измерение пространства и скорости .Также рассмотрите Set<String> как более оптимальную структуру данных вместо List.Рассмотрим Collections.singletonList("...") и emptyList().

Если строки в основном латинские-1, рассмотрим java 9, использующий более компактные байтовые массивы (в отличие от java 8).

С большими строками вы можете сжиматьbyte[] с использованием GZipOutputStream.

И последний вариант, исчерпывающий java -Xmx и физическую память: используйте базу данных .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...