好吧,在最好的情況下,我們假設字長為32位/ 4位元組(使用CompressedOops和CompressedClassesPointers).然後,映射條目由兩個單詞JVM開銷(klass指針和标記字),鍵,值,哈希碼和下一個指針組成,總共6個字,換句話說,24個位元組.是以,擁有15,000,000個條目執行個體将消耗360 MB.
此外,還有包含條目的數組. HashMap使用的幂為2的幂,是以對于15,000個條目,數組大小至少為16,777,216,消耗64 MiB.
然後,您有30,000個Integer執行個體.問題是map.put(i,i)執行兩次裝箱操作,并且鼓勵JVM在裝箱時重複使用對象,但不需要這樣做,并且在您可能完成的簡單程式中不會重複使用在優化器幹擾之前.
确切地說,前128個Integer執行個體被重用,因為對于-128 … 127範圍内的值,共享是必需的,但是實作通過在第一次使用時初始化整個緩存來實作,是以對于前128次疊代,它不會建立兩個執行個體,但緩存由256個執行個體組成,這是該數字的兩倍,是以我們最終再次使用30,000個Integer執行個體. Integer執行個體至少包含兩個JVM特定字和實際int值,它們将産生12個位元組,但由于預設對齊,實際消耗的記憶體将為16個位元組,可分為8個位元組.
是以,30,000個建立的Integer執行個體消耗480 MB.
這使得總共360 MB 64 MiB 480 MB,超過900 MB,使得1 GB的堆大小完全合理.
但這就是分析工具的用途.運作你的程式後,我得到了
請注意,此工具僅報告對象的已用大小,即Integer對象的12個位元組,而不考慮在檢視JVM配置設定的總記憶體時将注意到的填充.