You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ARC环境下TNetEncoding.GetBase64Encoding是否存在内存泄漏?我的修改正确吗?

关于TNetEncoding.GetBase64Encoding内存泄漏的判断与修改分析

你的判断完全正确,原代码确实存在内存泄漏风险,而且你的修改方向是对的,只是需要调整几个语法细节让代码能正常编译并正确工作。

原代码的问题所在

原代码试图用AtomicCmpExchange实现线程安全的单例初始化,但在非ARC(自动引用计数)环境下,引用计数的处理逻辑有漏洞:

class function TNetEncoding.GetBase64Encoding: TNetEncoding;
var
  LEncoding: TBase64Encoding;
begin
  if FBase64Encoding = nil then
  begin
    LEncoding := TBase64Encoding.Create;
    if AtomicCmpExchange(Pointer(FBase64Encoding), Pointer(LEncoding), nil) <> nil then
      LEncoding.Free;
    {$IFDEF AUTOREFCOUNT}
      FBase64Encoding.__ObjAddRef;
    {$ENDIF AUTOREFCOUNT}
  end;
  Result := FBase64Encoding;
end;

问题出在条件编译块的执行时机:

  • 当AtomicCmpExchange返回非nil时,说明其他线程已经抢先初始化了FBase64Encoding,我们创建的LEncoding会被正确释放,但此时代码仍然会对FBase64Encoding(其他线程的实例)调用__ObjAddRef。
  • 这个额外的引用计数永远不会被释放——因为类变量FBase64Encoding是全局持有的,不会主动减少引用,最终导致该实例的内存无法被回收,造成泄漏。

你的修改的正确性(及小调整)

你把__ObjAddRef移到了else分支(对应AtomicCmpExchange返回nil的情况),这个逻辑是完全正确的,只需要修正两个小细节:

class function TNetEncoding.GetBase64Encoding: TNetEncoding;
var
  LEncoding: TBase64Encoding;
begin
  if FBase64Encoding = nil then
  begin
    LEncoding := TBase64Encoding.Create;
    if AtomicCmpExchange(Pointer(FBase64Encoding), Pointer(LEncoding), nil) <> nil then
      LEncoding.Free
    else
    {$IFNDEF AUTOREFCOUNT} // 改为非ARC环境下才执行
      FBase64Encoding.__ObjAddRef;
    {$ENDIF}
  end;
  Result := FBase64Encoding;
end;

调整说明:

  1. 把{$IFDEF AUTOREFCOUNT}改成{$IFNDEF AUTOREFCOUNT}——因为ARC环境下,编译器会自动管理对象的引用计数,不需要手动调用__ObjAddRef;只有非ARC环境下才需要手动维护引用计数。
  2. 把占位符!!!ELSE!!!替换成标准的Delphielse关键字,否则代码无法编译。

这样修改后:

  • 当AtomicCmpExchange成功(返回nil)时,我们创建的LEncoding被赋值给FBase64Encoding,此时在非ARC环境下手动增加引用计数,确保实例能被正确持有。
  • 当AtomicCmpExchange失败时,我们只释放自己创建的LEncoding,不会对其他线程的实例做多余的引用操作,避免了内存泄漏。

总结

  • 你的判断(原代码存在内存泄漏)是准确的,问题源于非ARC环境下错误地给其他线程创建的实例增加了未释放的引用计数。
  • 你的修改方向完全正确,修正语法细节后,就能彻底解决这个内存泄漏问题。

内容的提问来源于stack exchange,提问作者zeus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:46:56