常見情況:功能測試通過、初期記憶體佔用正常,但資料規模增長時記憶體暴增。根本原因在於不瞭解 Java 資料結構的真實記憶體開銷。本文基於 32 位元系統(64 位元系統不適用)實測總結,助您寫出高品質、記憶體高效的程式碼。
| 類型 | byte | short | int | long | float | double | char | boolean |
|---|---|---|---|---|---|---|---|---|
| 位元組 | 1 | 2 | 4 | 8 | 4 | 8 | 2 | 1 |
範例:long[] data = new long[1000]; 佔用 8 × 1000 = 8000 bytes(陣列物件本身開銷可忽略)。
32 位元系統下,參考本質是受限指標,Object obj = null; 仍佔 4 bytes,Object[] objs = new Object[1000]; 至少佔 4000 bytes(全為 null 亦同)。
Object obj = new Object(); // 8 bytes 物件內容 + 4 bytes 參考 = 12 bytes
Object[] objs = new Object[1000];
for (int i=0; i<1000; i++) objs[i] = new Object();
// 至少 12 × 1000 = 12000 bytes
此規則決定所有包裝類型大小:
Integer = Object(8) + int(4) = 12 → 對齊至 16 bytesByte、Short、Character、Boolean 同理皆為 16 bytesbyte[] bytes = new byte[1000]; 結構等同:
class Array { int length; byte byte0; byte byte1; ... byte byte999; }
計算:4(參考) + [8(物件頭) + 4(length) + 1×1000(元素)] = 4 + 1012 = 1016 → 對齊 1016 + 4 = 1020 bytes
小陣列驗證:new byte[4] = 4 + [8+4+4] = 20 bytes;new byte[3] 同為 20 bytes(對齊)。
Byte[] bytes = new Byte[1000]; 佔用:
陣列本體:4 + [8 + 4 + 4×1000] = 4020 bytes
1000 個 Byte 物件:16 × 1000 = 16000 bytes
總計 ≈ 20020 bytes(vs byte[] 1020 bytes,差 20 倍!)
結論:嚴禁使用 Byte[]、Integer[] 等包裝類型陣列處理大量資料!
規則:物件內容 = 8 bytes 基礎 + 所有欄位大小總和(物件欄位只算 4 bytes 參考),總大小對齊至 8 倍數,再加 4 bytes 參考。
class Abc { int n; byte b; Object obj; }
// 內容:8 + 4 + 1 + 4 = 17 → 對齊 24 bytes
// 實例:4 + 24 = 28 bytes
class Abc { byte b; Object obj = null; } // 內容 8+1+4=13→16 bytes,實例 20 bytes
class Def { int n; byte b; Abc obj = new Abc(); }
// Def 實例:4 + [8+4+1+4(Abc參考)] + [Abc實例 20] = 44 bytes
class String {
private final char[] value; // 參考 4 bytes
private final int offset; // 4 bytes
private final int count; // 4 bytes
private int hash; // 4 bytes
}
// 最小 String 物件內容:8 + 4×4 = 24 bytes + 4 參考 = 28 bytes
精確計算:4 + 24 + [8 + 4 + 2×length](char[] 開銷)
String s = ""; → 28 + 16 = 44 bytesString s = "ab"; → 28 + 16 = 44 bytesString s = "abc"; → 28 + 24 = 52 bytesString[] s = new String[1000];
for (int i=0; i<1000; i++) s[i] = new String("相同長字串");
// 佔用量級:28 × 1000 = 28000 bytes(字串內容僅一份!)
String 實際佔用介於 28~44 bytes 之間,極度記憶體友善。
原系統使用 Hashtable 儲存 100 萬元素,改為 String[] + int[] 陣列配合二分搜尋,記憶體佔用大幅改善,排序僅需 2 秒,查詢效能接近 Hash 表。
jclass 結構