代码之家  ›  专栏  ›  技术社区  ›  Jens Mühlenhoff

当方法退出时,为什么此接口没有正确释放?

  •  2
  • Jens Mühlenhoff  · 技术社区  · 6 年前

    program Project1;
    
    {$APPTYPE CONSOLE}
    {$R *.res}
    
    uses
      Winapi.Windows,
      System.Generics.Collections,
      System.SysUtils;
    
    type
      TForm1 = class
      public
        Events: TList<TProc>;
        constructor Create;
        destructor Destroy; override;
      end;
    
      TTracingInterfacedObject = class(TInterfacedObject)
      public
        function _AddRef: Integer; stdcall;
        function _Release: Integer; stdcall;
      end;
    
      ISharedPtr<T> = interface
        ['{CC9EE6C5-F07B-40E5-B05D-2DFDBD3404A1}']
        function Get: T;
        function GetRefCount: Integer;
      end;
    
      ICatalog = interface
        ['{F421BBA8-8DA3-47EE-ADB9-DED26747472E}']
        function GetView: ISharedPtr<TForm1>;
        property View: ISharedPtr<TForm1> read GetView;
      end;
    
      ITree = interface
        ['{A1E2F71B-124B-48DB-B038-5F90AC5BE94B}']
        function GetId: TGUID;
        property Id: TGUID read GetId;
      end;
    
      TSharedPtr<T: class> = class(TTracingInterfacedObject, ISharedPtr<T>)
      private
        FObject: T;
      public
        constructor Create(const AObject: T);
        destructor Destroy; override;
        function GetRefCount: Integer;
        function Get: T;
      end;
    
      TCatalog = class(TTracingInterfacedObject, ICatalog)
      private
        FView: ISharedPtr<TForm1>;
      public
        constructor Create;
        function GetView: ISharedPtr<TForm1>;
      end;
    
      TTree = class(TTracingInterfacedObject, ITree)
      private
        FView: ISharedPtr<TForm1>;
      public
        constructor Create(const AView: ISharedPtr<TForm1>);
        function GetId: TGUID;
      end;
    
    function TTracingInterfacedObject._AddRef: Integer;
    begin
      OutputDebugString(PChar(ClassName + '._AddRef'));
      Result := inherited _AddRef;
    end;
    
    function TTracingInterfacedObject._Release: Integer;
    begin
      OutputDebugString(PChar(ClassName + '._Release'));
      Result := inherited _Release;
    end;
    
    constructor TForm1.Create;
    begin
      inherited;
      Events := TList<TProc>.Create;
    end;
    
    destructor TForm1.Destroy;
    begin
      Events.Free;
      inherited;
    end;
    
    constructor TSharedPtr<T>.Create(const AObject: T);
    begin
      inherited Create;
      FObject := AObject;
    end;
    
    destructor TSharedPtr<T>.Destroy;
    begin
      FObject.Free;
      inherited;
    end;
    
    function TSharedPtr<T>.Get: T;
    begin
      Result := FObject;
    end;
    
    function TSharedPtr<T>.GetRefCount: Integer;
    begin
      Result := FRefCount;
    end;
    
    constructor TCatalog.Create;
    begin
      inherited Create;
      FView := TSharedPtr<TForm1>.Create(TForm1.Create) as ISharedPtr<TForm1>;
    end;
    
    function TCatalog.GetView: ISharedPtr<TForm1>;
    begin
      Result := FView;
    end;
    
    constructor TTree.Create(const AView: ISharedPtr<TForm1>);
    begin
      inherited Create;
      FView := AView;
    end;
    
    function TTree.GetId: TGUID;
    begin
      Result := TGUID.Empty;
    end;
    
    procedure Main;
    var
      Catalog: ICatalog;
      Tree: ITree;
      Func: TFunc<TGUID>;
      Events: TList<TProc>;
      Event: TProc;
    begin
      Catalog := TCatalog.Create as ICatalog;
    
      Events := Catalog.View.Get.Events;
    
      Event := procedure
        begin
        end;
    
      Events.Add(Event);
    
      Tree := TTree.Create(Catalog.View) as ITree;
    
      Func := function: TGUID
        begin
          Result := Tree.Id;
        end;
    end;
    
    begin
      Main;
    
    end.
    

    我在决赛中设了一个断点 end.

    Debug Output: TSharedPtr<Project1.TForm1>._AddRef Process Project1.exe (3456)
    Debug Output: TCatalog._AddRef Process Project1.exe (3456)
    Debug Output: TSharedPtr<Project1.TForm1>._AddRef Process Project1.exe (3456)
    Debug Output: TSharedPtr<Project1.TForm1>._AddRef Process Project1.exe (3456)
    Debug Output: TSharedPtr<Project1.TForm1>._AddRef Process Project1.exe (3456)
    Debug Output: TTree._AddRef Process Project1.exe (3456)
    Debug Output: TSharedPtr<Project1.TForm1>._Release Process Project1.exe (3456)
    Debug Output: TSharedPtr<Project1.TForm1>._Release Process Project1.exe (3456)
    Debug Output: TCatalog._Release Process Project1.exe (3456)
    Debug Output: TSharedPtr<Project1.TForm1>._Release Process Project1.exe (3456)
    Source Breakpoint at $0047F675: C:\Users\Admin\Documents\Embarcadero\Studio\Projects\ViewFail\Project1.dpr line 168. Process Project1.exe (3456)
    

    • 这棵树被添加了一次,从未释放过,这不是我所期望的。

    为什么会这样?是否有一个参考周期在我缺失的地方?

    1 回复  |  直到 6 年前
        1
  •  6
  •   Dalija Prasnikar    6 年前

    • TForm1 Events
    • Catalog
    • Tree

    Main

    Event

    Anonymous method object -> Event 
                            -> Tree -> Events -> Event -> Anonymous method object
    

    nil