Вопрос (сейчас) о хранении большого количества данных, которые могут быть представлены с использованием примитивных типов, например int
, на карте. Некоторые ответы здесь очень вводят в заблуждение, на мой взгляд. Посмотрим почему.
Я изменил эталонный тест Trove для измерения времени выполнения и потребления памяти. Я также добавил PCJ к этому бенчмарку, который является еще одной библиотекой коллекций для примитивных типов (я широко ее использую). «Официальный» тест производительности не сравнивает IntIntMaps с коллекцией Java Map<Integer, Integer>
, вероятно, хранение Integers
и хранение ints
не совпадают с технической точки зрения. Но пользователь может не заботиться об этой технической детали, он хочет эффективно хранить данные, которые могут быть представлены ints
.
Сначала соответствующая часть кода:
new Operation() {
private long usedMem() {
System.gc();
return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
}
// trove
public void ours() {
long mem = usedMem();
TIntIntHashMap ours = new TIntIntHashMap(SET_SIZE);
for ( int i = dataset.size(); i-- > 0; ) {
ours.put(i, i);
}
mem = usedMem() - mem;
System.err.println("trove " + mem + " bytes");
ours.clear();
}
public void pcj() {
long mem = usedMem();
IntKeyIntMap map = new IntKeyIntOpenHashMap(SET_SIZE);
for ( int i = dataset.size(); i-- > 0; ) {
map.put(i, i);
}
mem = usedMem() - mem;
System.err.println("pcj " + mem + " bytes");
map.clear();
}
// java collections
public void theirs() {
long mem = usedMem();
Map<Integer, Integer> map = new HashMap<Integer, Integer>(SET_SIZE);
for ( int i = dataset.size(); i-- > 0; ) {
map.put(i, i);
}
mem = usedMem() - mem;
System.err.println("java " + mem + " bytes");
map.clear();
}
Я предполагаю, что данные приходят как примитивные ints
, что кажется нормальным. Но это подразумевает штраф за время выполнения для Java-утилиты из-за автобокса, который не является обязательным для каркасов примитивных коллекций.
Результаты выполнения (без gc()
вызовов, конечно) на WinXP, jdk1.6.0_10:
100000 пут операций 100000 содержит операции
коллекции Java 1938 мс 203 мс
Трос 234 мс 125 мс
pcj 516 мс 94 мс
Хотя это может показаться существенным, но это не причина для использования такой основы.
Причина в производительности памяти. Результаты для карты, содержащей 100000 int
записей:
коллекции java колеблются между 6644536 и 7168840 байтами
трое 1853296 байт
pcj 1866112 байт
Коллекции Java требуют более чем в три раза больше памяти по сравнению с примитивными платформами сбора. Т.е. вы можете хранить в три раза больше данных в памяти, не прибегая к дисковым операциям ввода-вывода, которые снижают быстродействие во времени. И это имеет значение. Читайте подробности о том, почему.
По моему опыту, высокое потребление памяти является самой большой проблемой производительности Java, что, конечно, также приводит к снижению производительности во время выполнения. Примитивные рамки коллекции могут действительно помочь здесь.
Итак: нет, java.util не является ответом. И «добавление функциональности» в коллекции Java - не главное, когда спрашивают об эффективности. Также современные коллекции JDK не "превосходят даже специализированные коллекции Trove".
Отказ от ответственности: эталонный тест здесь далек от завершения и не идеален. Он предназначен для того, чтобы показать, что я испытал во многих проектах. Примитивные коллекции достаточно полезны, чтобы терпеть подозрительные API - если вы работаете с большим количеством данных.