Вы можете попробовать две вещи:
Сделайте так, чтобы ваш hashCode
метод возвращал что-то более простое и эффективное, например, последовательный int
Инициализируйте вашу карту как:
Map map = new HashMap( 30000000, .95f );
Эти два действия значительно сократят объем повторной перестройки структуры, и я думаю, что их довольно легко проверить.
Если это не сработает, рассмотрите возможность использования другого хранилища, такого как СУБД.
EDIT
Странно, что установка начальной емкости снижает производительность в вашем случае.
см. Из javadocs :
Если начальная емкость больше, чем максимальное количество записей, деленное на коэффициент загрузки, операции перефразировки никогда не будут выполняться.
Я сделал микробич (который ни в коем случае не является окончательным, но, по крайней мере, подтверждает это)
$cat Huge*java
import java.util.*;
public class Huge {
public static void main( String [] args ) {
Map map = new HashMap( 30000000 , 0.95f );
for( int i = 0 ; i < 26000000 ; i ++ ) {
map.put( i, i );
}
}
}
import java.util.*;
public class Huge2 {
public static void main( String [] args ) {
Map map = new HashMap();
for( int i = 0 ; i < 26000000 ; i ++ ) {
map.put( i, i );
}
}
}
$time java -Xms2g -Xmx2g Huge
real 0m16.207s
user 0m14.761s
sys 0m1.377s
$time java -Xms2g -Xmx2g Huge2
real 0m21.781s
user 0m20.045s
sys 0m1.656s
$
Таким образом, использование начальной емкости падает с 21 до 16 с из-за повторного включения. Это оставляет нас с вашим hashCode
методом в качестве «области возможностей»;)
EDIT
Не является ли HashMap
Согласно вашему последнему изданию.
Я думаю, что вы действительно должны профилировать свое приложение и посмотреть, где оно потребляет память / процессор.
Я создал класс, реализующий тот же hashCode
Этот хеш-код дает миллионы коллизий, тогда записи в HashMap резко сокращаются.
Я перехожу с 21 на 16 в предыдущем тесте на 10 и 8 секунд. Причина в том, что hashCode провоцирует большое количество коллизий, и вы не храните 26M объектов, как вы думаете, но значительно меньшее число (около 20k, я бы сказал) Итак:
Проблемы НЕ ХЭШМАП находится где-то еще в вашем коде.
Пора получить профилировщик и выяснить, где. Я думаю, что речь идет о создании элемента или, возможно, вы пишете на диск или получаете данные из сети.
Вот моя реализация вашего класса.
note Я не использовал диапазон от 0 до 51, как вы, но от -126 до 127 для моих значений и повторяется, потому что я сделал этот тест, прежде чем вы обновили свой вопрос
Единственное отличие состоит в том, что в вашем классе будет больше столкновений, поэтому на карте будет храниться меньше предметов.
import java.util.*;
public class Item {
private static byte w = Byte.MIN_VALUE;
private static byte x = Byte.MIN_VALUE;
private static byte y = Byte.MIN_VALUE;
private static byte z = Byte.MIN_VALUE;
// Just to avoid typing :)
private static final byte M = Byte.MAX_VALUE;
private static final byte m = Byte.MIN_VALUE;
private byte [] a = new byte[2];
private byte [] b = new byte[3];
public Item () {
// make a different value for the bytes
increment();
a[0] = z; a[1] = y;
b[0] = x; b[1] = w; b[2] = z;
}
private static void increment() {
z++;
if( z == M ) {
z = m;
y++;
}
if( y == M ) {
y = m;
x++;
}
if( x == M ) {
x = m;
w++;
}
}
public String toString() {
return "" + this.hashCode();
}
public int hashCode() {
int hash = 503;
hash = hash * 5381 + (a[0] + a[1]);
hash = hash * 5381 + (b[0] + b[1] + b[2]);
return hash;
}
// I don't realy care about this right now.
public boolean equals( Object other ) {
return this.hashCode() == other.hashCode();
}
// print how many collisions do we have in 26M items.
public static void main( String [] args ) {
Set set = new HashSet();
int collisions = 0;
for ( int i = 0 ; i < 26000000 ; i++ ) {
if( ! set.add( new Item() ) ) {
collisions++;
}
}
System.out.println( collisions );
}
}
Использование этого класса имеет ключ для предыдущей программы
map.put( new Item() , i );
дает мне:
real 0m11.188s
user 0m10.784s
sys 0m0.261s
real 0m9.348s
user 0m9.071s
sys 0m0.161s