功能正確、記憶體看似正常,卻在資料量暴增時記憶體暴衝?根因在於不瞭解 JVM 物件真實佔用。本文針對 32 位元 HotSpot JVM,實測推導物件佈局鐵律,指導資料結構選型避坑。
| 型別 | 大小 |
|---|---|
| byte/boolean | 1 位元組 |
| short/char | 2 位元組 |
| int/float | 4 位元組 |
| long/double | 8 位元組 |
| 參考 | 4 位元組 |
long[1000] = 8,000 位元組 + 陣列物件頭;Object[] 即使全 null,每格 4 位元組參考空間照佔。
新物件大小 = 參考(4) + 物件頭(8) + 實例欄位大小總和 → 向上取 8 倍數
陣列大小 = 參考(4) + 物件頭(8) + length欄位(4) + 元素大小總和 → 向上取 8 倍數
| 程式碼 | 計算過程 | 實際佔用 |
|---|---|---|
new Object() | 4+8=12 → 16 | 16 位元組 |
new Integer(5) | int(4) → 4+8+4=16 | 16 位元組 |
new Byte(1) | byte(1) → 4+8+1=13 → 16 | 16 位元組(包裝類極度膨脹!) |
byte[1000] | 4+8+4+1000=1016 → 1016 | 1,020 位元組 |
Byte[1000] | 陣列 4+8+4+4000=4016 + 1000×16=16,000 → 20,020 | 約 20 KB(比 byte[] 膨脹 20 倍!) |
char[] value、offset、count、hash → 24 位元組 + 參考 4 = 28 位元組起跳。char[length] 另佔 16 + 2×length 位元組。String s = "abc" 僅佔 28 位元組參考;new String("abc") 強制新建物件+陣列,極度浪費。百萬筆Hashtable→ 改String[]+int[]並排,記憶體驟降、排序 2 秒內、二分查找媲美 Hash。
Byte[]、Integer[])。StringBuilder 替代 +,減少中間物件。-XX:+UseCompressedOops(JDK 6u23+ 預設開啟),64 位元 JVM 參考壓縮為 4 位元組,緩解膨脹。