10

让我们回到基础。坦率地说,我以前从未使用过NewDispose函数。然而,在我阅读了Embarcadero Technologies网站上的 New() 文档和包含的示例以及Delphi Basics 对 New()的解释之后,我的脑海中留下了一些问题:

除了节省少量内存之外,使用System.New()而不是局部变量有什么好处?

常见的代码示例New()或多或少如下:

  var
      pCustRec : ^TCustomer;
  begin
      New(pCustRec);
      pCustRec^.Name := 'Her indoors';
      pCustRec^.Age  := 55;
      Dispose(pCustRec);
  end;

在什么情况下上面的代码比下面的代码更合适?

  var
      CustRec : TCustomer;
  begin
      CustRec.Name := 'Her indoors';
      CustRec.Age  := 55;
  end;
4

6 回答 6

11

如果您可以使用局部变量,请这样做。这是一个几乎没有例外的规则。这会产生最干净和最有效的代码。

如果需要在堆上分配,请使用动态数组、GetMem 或 New。分配记录时使用新建。

无法使用堆栈的示例包括在编译时大小未知的结构或非常大的结构。但是对于作为 New 主要用例的记录,这些问题很少适用。

因此,如果您面临选择堆栈还是堆作为记录,那么堆栈总是正确的选择。

于 2013-01-09T08:08:40.333 回答
8

从另一个角度来看:

两者都可能遭受缓冲区溢出并且可以被利用

如果局部变量溢出,你会得到stack corruption

如果堆变量溢出,你会得到堆损坏

有人说堆栈损坏比堆损坏更容易利用,但通常情况并非如此

请注意,操作系统、处理器架构、库和语言中有各种机制试图帮助防止此类攻击。

例如,维基百科提到了DEP(数据执行保护)、ASLR(地址空间布局随机化)等。

于 2013-01-09T07:31:58.323 回答
7

局部静态变量在有限堆栈上保留空间。分配的内存位于堆上,基本上是所有可用的内存。

如前所述,堆栈空间是有限的,因此您应该避免使用大型局部变量以及按值传递的大型参数(参数声明中缺少var/ const)。

关于内存使用的一句话:
1. 简单类型(integercharstringdouble)直接位于堆栈上。使用的字节数可以由sizeof(variable)函数确定。
2. 同样适用于记录变量和数组。3. 指针和对象需要 4/8 字节。

于 2013-01-09T06:32:32.087 回答
4

每个对象(即类实例)总是在堆上分配。

值结构(简单的数字类型,仅包含这些类型的记录)可以在堆上分配。

动态数组和字符串内容总是在堆上分配。只有引用指针可以分配在堆栈上。如果你写:

  function MyFunc;
  var s: string;
  ...

这里,4/8 字节分配在堆栈上,但字符串内容(文本字符)将始终分配在堆上。

所以使用New()/Dispose()没有什么好处。如果它不包含引用计数类型,则可以使用GetMem()/FreeMem()代替,因为没有内部指针可以设置为零。

New()or的主要缺点Dispose()是,如果发生异常,则需要使用try...finally块:

  var
    pCustRec : ^TCustomer;
  begin
    New(pCustRec);
    try
      pCustRec^.Name := 'Her indoors';
      pCustRec^.Age  := 55;
    finally
      Dispose(pCustRec);
    end;
  end;

而在堆栈上分配让编译器以隐藏的方式为您完成:

  var
    CustRec : TCustomer;
  begin // here a try... is generated
    CustRec.Name := 'Her indoors';
    CustRec.Age  := 55;
  end;  // here a finally + CustRec cleaning is generated

这就是为什么我几乎从不使用New()/ Dispose(),而是在堆栈上分配,甚至在一个类中更好。2

于 2013-01-09T07:10:36.687 回答
2

堆分配的常见情况是对象必须比创建它的函数寿命长:

  1. 它作为函数结果或通过var/out参数直接或通过返回某个容器返回。

  2. 它被存储在某个对象、结构或集合中,这些对象、结构或集合在过程中被传递或以其他方式可访问(这包括向另一个线程发出信号/排队)。

于 2013-01-09T11:59:01.320 回答
1

在堆栈空间有限的情况下,您可能更喜欢从堆中分配。
参考。

于 2013-01-09T06:28:14.733 回答