New 和 GetMem 的不同之处

转载 2006年06月23日 12:44:00

今日想到一个问题:如果操作一个 record 指针中的字符串变量,会不会丢失 string 的内
存空间,造成内存泄漏?

结果是:使用 New() 分配的内存,会自动初始化 record 的内容,并且在 Dispose 时自动
清除所有已分配的内存,包括 string 或其他动态数组的内存。GetMem/FreeMem 没有这个
性质。事实上,New() 中调用了 GetMem,并且执行了一些初始化的操作。

代码如下:

type
  PMyRecord = ^TMyRecord;
  TMyRecord = record
    I: Integer;
    S: string;
    V: Variant;
  end;

{;$DEFINE NEW}

procedure TForm1.Button1Click(Sender: TObject);
var
  R: PMyRecord;
  I: Integer;
begin
  for I := 1 to 1024 do
  begin
{$IFDEF NEW}
    New(R); // 正确将 R.S 初始化
    SetLength(R.S, $FFFF);
    Dispose(R); // 正确释放 R.S 内存空间
{$ELSE}
    GetMem(R, SizeOf(TMyRecord));
    R.S := ''; // 出错
    SetLength(R.S, $FFFF);
    FreeMem(R);
{$ENDIF}
  end;
end;

===================================================

GetMem 只负责分配空间,不会负责清空刚分配的空间,如果需要分配来就
清空的空间可以用 AllocMem,AllocMem = GetMem + FillChar

===================================================

哦,我上面犯错误了,以为 S = 0 时也会出错,所以没有 FillChar,其实不会。

这样就可以正确测出结果了:
(将 $DEFINE NEW 前面的 ; 去掉,可以从任务管理器中查看二种方法的内存占用)

type
  PMyRecord = ^TMyRecord;
  TMyRecord = record
    I: Integer;
    S: string;
    V: Variant;
  end;

{;$DEFINE NEW}

procedure TForm1.Button1Click(Sender: TObject);
var
  R: PMyRecord;
  I: Integer;
begin
  for I := 1 to 1024 do
  begin
{$IFDEF NEW}
    New(R); // 正确将 R.S 初始化
    SetLength(R.S, $FFFF);
    Dispose(R); // 正确释放 R.S 内存空间
{$ELSE}
    GetMem(R, SizeOf(TMyRecord));
    FillChar(R^, SizeOf(TMyRecord), #0);
    SetLength(R.S, $FFFF);
    FreeMem(R); // 不会释放 R.S 内存空间 !!
{$ENDIF}
  end;
end;

===================================================

是的,FreeMem 不会释放其中的生存期自动管理的内容,因为在 FreeMem
看来,那些都是一致的二进制数据,没有任何意义可言。不过可以通过一个
Finalize 调用(或者 FinalizeRecord)解决该问题 big smile 我估计 Dispose 就直接
或间接调用了 Finalize big smile

===================================================

呵呵,不用估计,帮助中明确地说明了。

In Delphi code, FreeMem destroys the variable referenced by P and returns its memory to the heap. If P does not point to memory in the heap, a runtime error occurs. If P points to a structure that includes long strings, variants, dynamic arrays, or interfaces, call Finalize before calling Freemem.
......
Note:  It is preferable to use the New and Dispose procedures rather than GetMem and FreeMem. When using New and Dispose, there is no need to explicitly call Finalize.

===================================================

guttier wrote:
呵呵,不用估计,帮助中明确地说明了。

In Delphi code, FreeMem destroys the variable referenced by P and returns its memory to the heap. If P does not point to memory in the heap, a runtime error occurs. If P points to a structure that includes long strings, variants, dynamic arrays, or interfaces, call Finalize before calling Freemem.
......
Note:  It is preferable to use the New and Dispose procedures rather than GetMem and FreeMem. When using New and Dispose, there is no need to explicitly call Finalize.



这段英文我翻译一下。

“在DELPHI代码中,FreeMem根据变量所引用的指针释放内存,并将内存归还给堆。如果指针不是指向堆中的内存地址,将发生一个运行时错误。如果指针所指向的是一个数据结构,且其中包含有长字符串、Variants、动态数组、或接口,则在使用用FreeMem之前须调用Finalize ”
"注意:使用New 和 Dispose 过程要强于使用GetMem与FreeMem。但我们使用New和Dispose的时候,不需要显示的调用Finalize "

翻译完了。肯定有不准确的地方。
不过我有一个问题,内存分配既然new和Dispose要比GetMem与FreeMem容易使用,那么还有没有必要使用GetMem、FreeMem,在什么情况下使用它们?

===================================================

内存分配既然new和Dispose要比GetMem与FreeMem容易使用

“容易使用”通常只能是一个相对的概念,在这里,我们讨论指向结构体的指针,在这种情况下,New/Dispose 通常是易用的。但是它们是有局限的,就是那个指针指向的空间的大小必须能够在编译期间确定,它们才知道需要分配多大的空间。对于指向结构体的指针,这个值就是结构体的大小,这当然是确定的,所以能够使用它们,并且能够带来便利。
可是还有一些情况,例如你只有一个 Pointer 类型,这是无类型指针,你把它传给 New,编译器就不知道它指向的是什么内容,也就不知道它指向的空间有多大,也就不知道需要分配多少空间,就根本不能用,更不用说易用了。

还有没有必要使用GetMem、FreeMem,在什么情况下使用它们?

当然有了,如前面提到的,相对来说,New/Dispose 操作更为高层一些,我们通常用它们来操作指向结构体的指针,即是说指针指向的内容是编译期间就已知的数据结构。而当我们需要更加低级的去操作一些内存空间的时候,比如你要自己处理字符串的时候,你的指针指向的就是只有你自己才知道或者说是你自己去进行理解的内存空间,没有编译期间的明确的数据结构与之对应。这个时候,就要用到 GetMem/FreeMem 了。
所以说,New/Dispose 的局限性实际上是很大的,或者说适用范围是很小的,而 GetMem/FreeMem 给了我们充分的自由,试用范围更广。当然,具体选用哪个,还要看实际情况而定。


New 和 GetMem 的不同之处

如果操作一个 record 指针中的字符串变量,会不会丢失 string 的内 存空间,造成内存泄漏? 结果是:使用 New() 分配的内存,会自动初始化 record 的内容,并且在 Dispose...
  • shuihan20e
  • shuihan20e
  • 2009年01月02日 16:27
  • 508

[delphi]New 和 GetMem 的不同之处

 New 和 GetMem 的不同之处2006-12-23 14:56如果操作一个 record 指针中的字符串变量,会不会丢失 string 的内 存空间,造成内存泄漏? 结果是:使用 New() ...
  • yepemig
  • yepemig
  • 2009年01月12日 22:42
  • 434

New 和 GetMem 的不同之处====转帖收藏

 如果操作一个 record 指针中的字符串变量,会不会丢失 string 的内 存空间,造成内存泄漏?结果是:使用 New() 分配的内存,会自动初始化 record 的内容,并且在 Dispose...
  • henreash
  • henreash
  • 2009年06月02日 11:07
  • 828

【设计模式 2】设计模式的来源,及其相混淆的模型、框架、架构区别

导读:周日,又给徒弟验收项目了。以往常的习惯一样,每次验收,我都陪着徒弟一起总结学习过程中的问题,然后互相交流。这次,一个徒弟验收的是设计模式,一个徒弟验收的是UML,本篇博客,就先谢谢设计模式的东西...
  • u013034889
  • u013034889
  • 2015年12月23日 20:33
  • 964

java语言和C语言的跨平台原理

java跨平台原理(优点:一次编译,到处运行) C语言跨平台原理:(优点:多次编译,到出运行)...
  • lll2016
  • lll2016
  • 2016年09月12日 16:22
  • 249

getmem

在c++stl程序媛开发指南上看到一个getmem的例子 template   void getmem(T*& oldmem,int elems) { typedef int cntr; c...
  • nasasaga
  • nasasaga
  • 2012年02月01日 19:18
  • 235

详解“InnoDB”和“MyISAM”的不同之处

InnoDB和MyISAM是许多人在使用MySQL时最常用的两个表类型,这两个表类型各有优劣,视具体应用而定。基本的差别为:MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持。MyISA...
  • shaobingj126
  • shaobingj126
  • 2010年06月22日 14:00
  • 454

dpkg 和 rpm 的常用方法比较

rpm vs. dpkg 常用參數對照 安裝 目的 rpm 用法 dpkg 用法 安裝指定套件 rpm -i pkgfile.rpm dpkg -...
  • s464036801
  • s464036801
  • 2012年05月12日 22:06
  • 1154

内存池的一种实现

#include #include #include #include #include "Const.h" #include "UtilityFunc.h" #include "...
  • yaxf999
  • yaxf999
  • 2012年05月30日 13:52
  • 565

C++ 指针与引用 知识点 小结

指针可以指向变量、数组、字符串、函数、甚至结构体。即指针可以指向不同数据对象。指针问题 包括 常量指针、数组指针、函数指针、this指针、指针传值、指向指针的指针 等。主要知识点包括:1.指针与引用在...
  • u013630349
  • u013630349
  • 2015年08月13日 00:04
  • 1296
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:New 和 GetMem 的不同之处
举报原因:
原因补充:

(最多只允许输入30个字)