Pertanyaannya adalah (sekarang) tentang menyimpan banyak data, yang dapat direpresentasikan menggunakan tipe primitif seperti int
, dalam Peta. Beberapa jawaban di sini sangat menyesatkan menurut saya. Mari kita lihat alasannya.
Saya memodifikasi benchmark dari trove untuk mengukur baik runtime maupun konsumsi memori. Saya juga menambahkan PCJ ke benchmark ini, yang merupakan pustaka koleksi lain untuk tipe primitif (saya menggunakannya secara ekstensif). Tolok ukur harta 'resmi' tidak membandingkan IntIntMaps dengan Java Collection Map<Integer, Integer>
, mungkin penyimpanan Integers
dan penyimpanan ints
tidak sama dari sudut pandang teknis. Tetapi pengguna mungkin tidak peduli dengan detail teknis ini, dia ingin menyimpan data yang dapat direpresentasikan dengan ints
efisien.
Pertama, bagian kode yang relevan:
new Operation() {
private long usedMem() {
System.gc();
return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
}
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();
}
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();
}
Saya menganggap datanya primitif ints
, yang tampaknya waras. Tapi ini menyiratkan hukuman waktu proses untuk java util, karena auto-boxing, yang tidak diperlukan untuk framework koleksi primitif.
Hasil runtime (tanpa gc()
panggilan, tentu saja) di WinXP, jdk1.6.0_10:
100000 operasi put 100000 berisi operasi
koleksi java 1938 ms 203 ms
harta karun 234 ms 125 ms
pcj 516 ms 94 ms
Meskipun ini mungkin sudah tampak drastis, ini bukanlah alasan untuk menggunakan kerangka kerja seperti itu.
Alasannya adalah kinerja memori. Hasil untuk Peta yang berisi 100000 int
entri:
koleksi java berosilasi antara 6644536 dan 7168840 byte
harta karun 1853296 byte
pcj 1866112 byte
Koleksi Java membutuhkan lebih dari tiga kali memori dibandingkan dengan kerangka kerja koleksi primitif. Yaitu Anda dapat menyimpan data tiga kali lebih banyak dalam memori, tanpa menggunakan disk IO yang menurunkan kinerja runtime menurut besarnya. Dan ini penting. Baca skalabilitas tinggi untuk mencari tahu alasannya.
Menurut pengalaman saya, konsumsi memori yang tinggi adalah masalah kinerja terbesar dengan Java, yang tentu saja menghasilkan kinerja runtime yang lebih buruk juga. Kerangka kerja koleksi primitif dapat sangat membantu di sini.
Jadi: Tidak, java.util bukanlah jawabannya. Dan "menambahkan fungsionalitas" ke koleksi Java bukanlah intinya ketika bertanya tentang efisiensi. Juga koleksi JDK modern tidak "mengungguli bahkan koleksi Trove khusus".
Penafian: Tolok ukur di sini masih jauh dari lengkap, juga tidak sempurna. Ini dimaksudkan untuk menyampaikan poin, yang telah saya alami dalam banyak proyek. Koleksi primitif cukup berguna untuk mentolerir API mencurigakan - jika Anda bekerja dengan banyak data.