【问题标题】:Am I creating a memory leak here?我在这里创建内存泄漏吗?
【发布时间】:2010-11-26 14:01:48
【问题描述】:

一个很简单的问题:

type

TMyRecord = Record
  Int: Integer;
  Str: String;
end;

PMyRecord = ^TMyRecord;

var
  Data: PMyRecord;
begin
  New(Data);
  Data.Int := 42;
  Data.Str := 'Test';
  Dispose(Data);
end;

我的问题是,我是否在这里创建了内存泄漏(使用String)?我应该在拨打Dispose之前先拨打Data.Str := '';吗?

谢谢!

【问题讨论】:

    标签: delphi memory-management memory-leaks delphi-7


    【解决方案1】:

    不,Dispose 正确释放记录中的字符串和动态数组,包括嵌套的。 GetMem/FreeMem(Data) 确实会造成内存泄漏。

    【讨论】:

    • 将变体、引用计数接口甚至匿名函数添加到列表中,我认为引用计数的所有内容都在Dispose() 上发布。
    • GetMem/FreeMem 需要调用 Finalize()。检查帮助中的 Finalize 以了解当 Dispose() 无法使用时它的作用。
    • @ldsanson:New = GetMem+Initialize 和 Dispose = Finalize+FreeMem - 检查 System.pas。这些只是两个函数的包装器。
    【解决方案2】:

    如果在您的分配/解除分配对之间引发异常,则表示内存泄漏。像这样保护它们是正常的:

    New(Data);
    Try
      Data.Int := 42;
      Data.Str := 'Test';
    Finally
      Dispose(Data);
    End;
    

    【讨论】:

    • 您最好将记录分配在堆栈中,或者在动态数组中。两者都会初始化每个记录项的内容。 try..finally 对于堆分配来说是强制性的,就像一个 TObject.Create 需要一个对应的 try..finally Free。如果您的记录是通过动态数组或堆栈分配的,则此类 try...finally 将由编译器自动创建。
    • @ArnaudBouchez 如果需要数组,请在数组中分配。如果您想要单个记录,则不合适。如果记录的生命周期必须超过创建记录的范围,则在堆上分配 New 而不是堆栈。
    • @DavidHeffernan 我给你的答案+1,这是正确的。我只是想指出一些替代方案。使用New/Dispose 在堆上分配记录很奇怪,因为您手头有class 只是为了这个目的。记录上的指针不如 class 实例干净——它具有整个 OOP 范式,而记录没有。
    • @Arnaud 也许。如果结构始终是堆分配的,那么类是明智的。但是,您希望能够在堆栈或堆上分配的结构呢?
    【解决方案3】:

    不,你不是,String 被删除时会自行清理自己的内存。

    【讨论】:

    • 实际上:当包含结构完成时,字符串会自行释放。
    【解决方案4】:

    如果你想要内存泄漏,afaik 你必须使用 TP 对象 :-) 它们是 Delphi 中唯一没有初始化/最终化的结构化类型

    【讨论】:

    • TP 对象被初始化。它们的处理方式与记录相同。在 Delphi 添加了对带有方法的记录的支持之前,我们实际上已广泛使用它们。
    • 如果您使用动态数组或在堆栈上实例化它们,记录或对象不会造成内存泄漏,这很常见。只有在堆分配时才需要 New() 和 Dispose()。使用 New(aRecordPointer) 并不比使用 anObject.Create 难...
    • groups.google.com/group/comp.lang.pascal.delphi.misc/msg/… 承认,它适用于具有 VMT 的 TP 对象。所以作为记录的使用是可以的,作为对象的使用不是
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-22
    相关资源
    最近更新 更多