最簡單的 Java 程式 new int; 無需釋放,C++ 同樣寫法卻被視為洩漏。本文核心觀點:若程式空間複雜度 O(1) 或階段性 O(n),只 new 不 delete 完全可行。關鍵在於引入 AutoFreeAlloc —— 階段性自動回收配置器。
DocX 遞迴處理大量原始碼檔案,生成 XML/HTML/CHM,運行久後因記憶體耗盡崩潰。修正僅三步:
std::AutoFreeAlloc alloc;new T(args) → STD_NEW(alloc, T)(args);new T[n] → STD_NEW_ARRAY(alloc, T, n)alloc.clear() 批量回收。自此零洩漏、零崩潰。展示「階段性配置、階段性回收」模式威力。
| 空間複雜度 | 模式 | 方案 |
|---|---|---|
| O(1) | 常數記憶體 | 只 new 不 delete 無妨 |
| O(n) = n × O(1) | 階段性批量 | AutoFreeAlloc + 週期性 clear() |
| O(t) 隨時間增長 | 長期運行 (Word/Excel) | AutoFreeAlloc 不直接適用,需引入分代 GC |
文件分析常建立只讀 DOM 樹。以 Document 持有 AutoFreeAlloc alloc,所有節點配置自同一池:
class Document {
AutoFreeAlloc alloc;
ObjectA* getA() { if (!m_a) m_a = STD_NEW(alloc, ObjectA)(this); return m_a; }
};
// 刪除 Document 瞬間,整棵 DOM 樹連同配置器一併銷毀,零洩漏風險。
若需長期運行通用 GC,可在 AutoFreeAlloc 基礎上實現「複製式 GC」:
Object* gc(AutoFreeAlloc& oldAlloc, Object* root, AutoFreeAlloc& newAlloc) {
Object* root2 = root->clone(newAlloc); // 遍歷活躍物件複製至新池
oldAlloc.clear(); // 整體丟棄舊池 (含垃圾)
return root2;
}
clone(alloc) (類似 Java 物件圖遍歷)。clone 即為遍歷協議。AutoFreeAlloc (除非單執行緒小工具),優先作為成員或區域變量傳遞。clone 實作非負擔:許多物件設計天然需要複製語義,GC 只是複用。「C++ 程式員同樣可以像 GC 語言開發者那樣大膽 new,關鍵在擁有正確的配置器抽象。」