首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

C++ 智慧指標實現垃圾回收與循環引用破解:引用計數 + 標記掃描混合機制

     編輯:Java 相關知識

C++ 缺乏內建 GC,手動 new/delete 易導致記憶體洩漏或雙重釋放。本文設計一套「引用計數 + 循環引用偵測」混合機制:CPtrManager 統管所有堆上物件引用計數,auto_ptr 智慧指標自動增減計數;當離開作用域後殘留計數>0 物件,啟動背景執行緒掃描「互鎖群組」(所有智慧指標皆位於受管物件內部),強制釋放。並引入 CMutex 實現執行緒安全,完整程式碼可直接整合至專案。

架構總覽

類別職責
CPtrManager全域單例,管理 CPtr 陣列、引用計數、標記分配、循環掃描執行緒
CPtr包裝單一堆物件:原始指標、大小、引用計數、擁有者智慧指標陣列與標記
auto_ptr<T>智慧指標模板:建構/複製/賦值/析構自動增減計數,支援 parent_autoptr 介面供強制釋放
CMark / CMarkTable掃描階段快照:拷貝 CPtr 資訊、識別「全在堆上」物件、遞迴剔除假鎖、分組釋放

關鍵演算法

1. 引用計數自動管理

void* operator new(size_t sz) { return thePtrManager.MallocPtr(sz); }
void operator delete(void* p) {
    int mark = thePtrManager.GetMarkFromPtr(p);
    if (mark > 0) thePtrManager.UserDelete(mark);
    free(p);
}
template<class T> auto_ptr<T>::auto_ptr(T* ptr) {
    pointee = ptr;
    mark = thePtrManager.GetMarkFromPtr(ptr);
    if (mark > 0) thePtrManager.AddCount(mark, pointee);
}
template<class T> void auto_ptr<T>::Remove() {
    if (pointee && thePtrManager.Release(mark, pointee)) {
        if (thePtrManager.GetCount(mark, pointee) == 0) delete pointee;
    }
    pointee = null; mark = 0;
}

2. 智慧指標位置判斷(堆 vs 棧)

int CPtrManager::GetAutoMark(void* smartPtr) {
    for (CPtr* cp : m_ptr) {
        int base = (int)cp.GetPtr();
        int limit = base + cp.GetPtrSize();
        if ((int)smartPtr >= base && (int)smartPtr <= limit) return cp.m_mark;
    }
    return 0; // 在棧上
}

原理:若智慧指標地址落在某受管物件記憶體區間內,則該智慧指標「內嵌」於該物件中。

3. 循環引用偵測與釋放

  1. 快照:CMarkTable.CopyAllMark() 拷貝所有 CPtr 至 CMark,避免鎖住主管理器。
  2. 候選集:GetLockMark() 篩選「所有擁有者智慧指標皆在堆上」的 CMark 進入 CLockMarkArray。
  3. 剔除假鎖:RemoveUnlockMark() 反覆移除「擁有者包含非候選集智慧指標」的項目,直至收斂。
  4. 分組釋放:RemoveGroup(automark) 遞迴標記相連群組,最後呼叫 CMark.Release() → parent_autoptr.Release() → auto_ptr.Remove() 強制釋放。

執行緒安全

  • CPtrManager.mutex 保護全域結構(配置、計數增減、掃描快照)。
  • CPtr.mutex 保護單一物件的擁有者陣列操作。
  • 掃描執行緒以 THREAD_PRIORITY_ABOVE_NORMAL 執行,透過 bWrite 旗標協調寫入鎖。

整合指南

  1. 將 SmartPtr.h/cpp 加入專案。
  2. 在 CWinApp 派生類中宣告全域 CPtrManager thePtrManager; 確保最後析構。
  3. 原本 new Type 回傳指標直接指派給 auto_ptr<Type>。
  4. 舊代碼介面:需釋放所有權 → 用 auto_ptr 接收/傳遞;僅借用 → 繼續用裸指標。

效能與限制

  • 優點:零侵入式業務邏輯、自動破解循環引用、執行緒安全。
  • 缺點:高併發下 CPtrManager 全域鎖成為瓶頸;大量短命物件頻繁觸發掃描影響延遲;需編譯器支援 RTTI 與例外處理。
  • 現代替代:C++11 std::shared_ptr + std::weak_ptr 手動打破循環,或引入 Clang Static Analyzer 靜態檢測。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved