Delphi 字典释放

标签 delphi dictionary memory-leaks tdictionary

我实现了以下类:

type
  TUtilProcedure = procedure(var AJsonValue: TJSONObject);

  TCallback = class
  private
    FName: string;
    FProcedure: TUtilProcedure;
    FAnnotation: string;
  public
    constructor Create(AName: string; AProcedure: TUtilProcedure; AAnnotation: string); overload;
    constructor Create(ACallback: TCallback); overload;
    property Name: string read FName;
    property Proc: TUtilProcedure read FProcedure;
    property Annotation: string read FAnnotation;
 end;

然后我有一个全局变量:

procedures: TDictionary<string, TCallback>;

OnFormActivate 过程中,我初始化 procedures 变量:

procedures := TDictionary<string, TCallback>.Create();
procedures.Add('something', TCallback.Create('sth', @proc, 'annotation')); 
// ....

然后在OnFormClose中我释放它:

procedures.Clear;
procedures.Free;

我的代码是否泄漏内存?如果是这样,释放字典的正确方法是什么? 据我所知,迭代并不是一个好主意。

最佳答案

代码会泄漏内存,因为 TDictionary 中包含的对象不会自动释放。

如果需要在字典中存储对象,则采用TObjectDictionary代表了一种更好的方法。

如果您希望自动释放字典中包含的对象,请在创建集合实例时使用 doOwnsValues 标志。

  • 当变量确实是全局的(即在单元的 interface 部分的 var 下声明)时,它应该在单元本身的初始化终结部分中创建和销毁。

    . . .
    var
      procedures: TObjectDictionary<string, TCallback>;
    . . .
    initialization
      procedures:= TObjectDictionary<string, TCallback>.Create([doOwnsValues]);
    finalization
      procedures.Free;
    
  • 当您的变量属于表单类本身时,您应该在表单的 OnCreate 事件中创建字典。

    . . .
    public
      procedures: TObjectDictionary<string, TCallback>;
    . . .
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      procedures:= TObjectDictionary<string, TCallback>.Create([doOwnsValues]);
    end;
    

    在表单的 OnDestroy 事件中释放字典:

    procedure TForm1.FormDestroy(Sender: TObject);
    begin
      procedures.Free;
    end;
    
  • 此外,如果您希望访问属于该类的变量而不需要类本身的实例(这在许多编程语言中称为静态变量) ,您可以将字典声明为 class var 并可以选择通过 class property 访问它;在这种情况下,最好在类构造函数类析构函数中创建和销毁集合。

    . . .
    TMyClass = class
      private
        class constructor Create;
        class destructor Destoy;
      public
        class var procedures: TObjectDictionary<string, TCallback>;
    end;
    . . .
    class constructor TMyClass.Create;
    begin
      procedures := TObjectDictionary<string, TCallback>.Create([doOwnsValues]);
    end;
    
    class destructor TMyClass.Destoy;
    begin
      procedures.Free;
    end;
    
<小时/>
TCallback = class
  private
    FName: string;
    FProcedure: TUtilProcedure;
    FAnnotation: string;
  public
    constructor Create(AName: string; AProcedure: TUtilProcedure; AAnnotation: string); overload;
    constructor Create(ACallback: TCallback); overload;
    property Name: string read FName;
    property Proc: TUtilProcedure read FProcedure;
    property Annotation: string read FAnnotation;
end;

顺便说一句,TCallback 类不需要指定析构函数,因为它只拥有两个字符串和一个指向过程的指针。因此从 TObject 继承的默认析构函数就足够了。

关于Delphi 字典释放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32221454/

相关文章:

delphi - 我如何在Delphi中使用jclcompression,有例子吗?

c++ - 如何正确传递 C/C++ *(PUCHAR)(..)?

R:来自 ggmap 的 get_map()/get_googlemap() 错误

java - 理解 HashMap 键- java

r - R 3.6.0中的data.table包是否存在内存泄漏?

c++ - 如何为局部变量分配内存?

delphi - 如何判断Tpicture是否包含Jpeg?

delphi - LongInt 与 Integer、LongWord 与 Cardinal 的区别

Python 加速在范围字典中搜索值

objective-c - UIImage 导致内存泄漏