J2ME 裝置(功能機、早期智慧型手機)堆疊記憶體極其有限(典型 200KB-1MB)。記憶體溢出(OOM)是開發頭號殺手。GC 非即時、不可靠,所有非基本型別物件必須手動釋放 是鐵律。
// ❌ 錯誤:依賴 GC,舊場景物件與新場景物件並存導致 OOM
gameLogic = new GameLogic(); // 主選單 → 遊戲
// ✅ 正確:顯式置空舊引用,再建立新物件
gameLogic = null; // 釋放舊場景引用
System.gc(); // 建議提示 GC(不保證立即執行)
gameLogic = new GameLogic();
// ❌ 危險:先建立新物件,再釋放舊引用 → 瞬間雙物件共存
logic = new Logic();
// ✅ 安全:先釋放,再建立
logic = null;
logic = new Logic();
原代碼 a = new Logic() 期間舊 a 仍被引用,新物件建立完成前記憶體峰值雙倍。
// 關鍵點插桿監控
System.out.println("Free: " + Runtime.getRuntime().freeMemory() + " bytes");
// 觀察曲線,定位洩漏點
// 載入
Image img = Image.createImage("/res/bg.png");
// 使用完畢立即釋放
img = null; // 讓 GC 回收底層像素緩衝區
// 單例快取管理器
class ResourceManager {
private static Hashtable cache = new Hashtable();
public static Image getImage(String path) {
Image img = (Image) cache.get(path);
if (img == null) {
try {
img = Image.createImage(path);
cache.put(path, img);
} catch (IOException e) { return null; }
}
return img;
}
public static void releaseAll() {
cache.clear();
System.gc();
}
}
Image.createImage(width, height) 作為離屏緩衝g.drawImage(offscreen, 0, 0, 0) 後立即釋放離屏緩衝
// ❌ 循環拼接:產生大量臨時 String/StringBuffer
String s = "";
for (int i=0; i<100; i++) s += i;
// ✅ StringBuilder(J2ME 支援 CLDC 1.1+)
StringBuilder sb = new StringBuilder(200);
for (int i=0; i<100; i++) sb.append(i);
String result = sb.toString();
| 集合 | 記憶體開銷 | 適用場景 |
|---|---|---|
基本型別陣列 int[] | 最低(連續記憶體) | 固定大小、高頻存取、基本型別 |
| Vector | 中等(Object[] + 同步開銷) | 動態陣列、需執行緒安全 |
| Hashtable | 最高(Entry 物件 + 雜湊表) | 鍵值查找、資料關聯 |
能用基本型別陣列絕不用 Vector;能用 Vector 絕不用 Hashtable。
// ❌ 自動裝箱(J2ME 多不支援,但邏輯同)
Integer i = 100; // 新物件
// ✅ 基本型別
int i = 100;
// ❌ 字串格式化
String s = "x=" + x + ", y=" + y;
// ✅ 直接拼接或預分配 Builder
Runtime.freeMemory() 關鍵點記錄,建立基準線J2ME 記憶體優化核心心法:不信任 GC、手動管理生命週期、最小化物件圖、基本型別優先。這些習慣不僅能在資源受限裝置存活,更能養成寫出高效率 Java 代碼的基本功,對後續 Android/Java SE 開發同樣受用。