首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> Delphi

Delphi 設計簡易物件垃圾回收框架:解決多執行緒環境下物件過早釋放問題

     編輯:Delphi

問題背景:Socket 事件觸發導致物件過早銷毀

在壓力測試工具(客戶端/伺服器架構,Socket 通訊)中,高併發呼叫量下頻繁出現 EAccessViolation、EInvalidCast、斷言失敗等錯誤。追蹤發現:伺服器端 OnDisconnect 事件中直接銷毀連線對應的呼叫物件(FLine),但發送資料的呼叫堆疊中後續程式碼仍嘗試存取該物件,導致「用後釋放」錯誤。

// 問題代碼:OnDisconnect 中直接銷毀物件
procedure TServer.ServerClientDisconnect(Sender: TObject; Socket: TCustomWinSocket);
begin
  ...
  FLines.DestroyLineBySocket(Socket); // 不當時機釋放物件
  ...
end;

// 呼叫端代碼片段
FLine.DoSomething;
FLine.SendSocketData;  // 觸發 OnDisconnect,物件被銷毀
FLine.DoOtherThings;   // 此處存取已釋放物件 → AV/InvalidCast

解決方案:延遲銷毀機制(垃圾回收池)

採用「延遲銷毀」策略:OnDisconnect 將待銷毀物件丟入垃圾池,在訊息迴圈空閒時機(如 Application.OnIdle 或定時器)統一回收。核心要求:線程安全、可控制回收頻率、自動清理。

垃圾回收器實作(untGarbageCollector)

unit untGarbageCollector;

interface
uses Classes;

type
  TGarbageCollector = class(TObject)
  private
    FList: TThreadList; // 線程安全列表
  public
    constructor Create;
    destructor Destroy; override;
    procedure Put(const AObject: TObject);           // 丟入垃圾池
    procedure Recycle(const MaxCount: Integer);      // 批次回收(限制數量)
  end;

function GarbageCollector: TGarbageCollector; // 單例存取

implementation
var _GarbageCollector: TGarbageCollector;

function GarbageCollector: TGarbageCollector;
begin
  if not Assigned(_GarbageCollector) then
    _GarbageCollector := TGarbageCollector.Create;
  Result := _GarbageCollector;
end;

constructor TGarbageCollector.Create;
begin
  FList := TThreadList.Create;
end;

destructor TGarbageCollector.Destroy;
begin
  try
    Recycle(FList.LockList.Count); // 程式結束前全數回收
  finally
    FList.UnlockList;
  end;
  FList.Free;
  inherited;
end;

procedure TGarbageCollector.Put(const AObject: TObject);
begin
  FList.LockList.Add(AObject);
  FList.UnlockList;
end;

procedure TGarbageCollector.Recycle(const MaxCount: Integer);
var I: Integer; AList: TList;
begin
  AList := FList.LockList;
  try
    I := 0;
    while (AList.Count > 0) and (I < MaxCount) do
    begin
      TObject(AList.Last).Free; // 釋放物件
      AList.Delete(AList.Count - 1);
      Inc(I);
    end;
  finally
    FList.UnlockList;
  end;
end;

initialization
finalization
  if Assigned(_GarbageCollector) then _GarbageCollector.Free;
end.

使用範例與擴展應用

基本用法:

uses untGarbageCollector;

var Obj: TMyObject;
begin
  Obj := TMyObject.Create;
  GarbageCollector.Put(Obj); // 非立即釋放,延遲回收
end;

// 定時器或 OnIdle 中呼叫回收
GarbageCollector.Recycle(10); // 每次最多回收 10 個物件

應用場景:

  • 防止物件過早銷毀: 事件處理中無法立即判斷物件是否仍被其他程式碼引用時
  • 效能優化(以空間換時間): 批次處理任務產生大量臨時物件,任務完成後延遲銷毀,避免頻繁記憶體操作阻塞主執行緒
  • 可擴展為時間限制回收: 每次回收耗時不超過 N 毫秒,進一步平滑效能曲線

這個輕量級框架解決了多執行緒環境下物件生命週期管理的經典難題,代碼簡潔且易於整合進既有專案。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved