Delphi New,Getmem,ReallocMem联系与区别
来自:http://www.cnblogs.com/jsrgren/archive/2011/10/31/2270353.html
----------------------------------------------------------------------------------------
procedure New(var P: Pointer); {为一个指针变量分配内存,会自动计算指针所指数据结构需要空的空间大小}
procedure GetMem(var P: Pointer; Size: Integer); {分配一个指定大小的内存块(连续),并用P指向它}
procedure ReallocMem(var P: Pointer; Size: Integer); {重新分配指定大小内存块,参数P必须是nil或者指向一个由GetMem, AllocMem, 或 ReallocMem分配的内存变量,其分配的内存是连续的,会把前面已有的数据移到新分配的内存中去}
通常采用New分配内存比较好。
一、New和GetMem都可以为指针类型动态分配内存,并且Delphi不会对由此分配的内存进行管理,即必须有相应的代码对其进行释放,否则内存将“丢失”,直到应用程序结束。
二、New分配的内存必须由Dispose来释放;GetMem分配的内存必须由FreeMem来释放;
三、New根据指针类型来自动计算需要分配的内存尺寸;GetMem必须指定尺寸;
因此,对于类型指针,一般用New和Dispose来进行管理;对于内存尺寸随机的指针(典型地如PChar),一般用GetMem和FreeMem来进行管理。从另一方面来说,在很多时候用哪一对例程都可以进行动态内存管理。
******************************************
转自http://blog.sina.com.cn/s/blog_62fd44430100v79l.html
如果操作一个 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)解决该问题 我估计 Dispose 就直接
或间接调用了 Finalize
===================================================
呵呵,不用估计,帮助中明确地说明了。
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 给了我们充分的自由,试用范围更广。当然,具体选用哪个,还要看实际情况而定。
Delphi New,Getmem,ReallocMem联系与区别的更多相关文章
- New,Getmem,ReallocMem联系与区别(转)
procedure New(var P: Pointer); {为一个指针变量分配内存,会自动计算指针所指数据结构需要空的空间大小} procedure GetMem(var P: Pointer; ...
- delphi 与 C++的基本语法区别
[1]“=”符号 (1)“=”作为比较符.但是,当定义const常量时,“=”又表示赋值符号.而“:=”作为赋值符号. (2)“=”只表示赋值符号 [2]结构体 (1)record 作为结构体 (2) ...
- Delphi中Self和Sender的区别
在事件处理程序参数表中,至少含有一个参数Sender,它代表触发事件处理程序的构件,如在上例中,Sender就指Button2,有了Sender参数,可以使多个构件共用相同的事件处理程序,如下例: ...
- Delphi各销售版本之间的区别
初步的区别: http://www.embarcadero.com/products/delphi/product-editions http://www.embarcadero.com/fr/pro ...
- Delphi Thread.Queue与Synchronize的区别(差别: Synchronize是阻塞,Queue是非阻塞)
前话: 其实大家要学会看源码, 我接下来要说的这些东东,与其等别人讲,还不如自己搞几个代码试一下,印象还深刻点 TThread.Queue和TThread.Synchronize的区别, 效果上:二 ...
- Delphi Web Service和ISAPI的区别与联系 转
Web Service和ISAPI的区别与联系 1.Web Service 是一种新的web应用程序分支,他们是自包含.自描述.模块化的应用,可以发布.定位.通过web调用.Web Service ...
- Delphi中nil和null的区别
nil:空指针,空地址,对象也是指针,可以object := nil;null:是一个未定义值的变量,既不是0也不代表空字符串,它是未定义的.
- Delphi 类方法和普通方法的区别 .
//类声明 TMyClass = class public class procedure MyProc; //类方式 constructor Create; //Crea ...
- Delphi中Owner和Parent的区别
Owner为创建者,Parent为容器 他们的类型不同,Owner为TComponent(元件),Parent为TWinControl(窗体控件) Parent属性是指构件的包容器,构件只能在此范围内 ...
随机推荐
- 【linux】linux中tree的安装
# 2018/7/29 10:17:46测试成功! 一 Tree命令简介 tree是一种递归目录列表命令,产生一个深度缩进列表文件. 二 Tree命令安装 1.下载安装包,地址:http://mama ...
- PAT 1086 就不告诉你
https://pintia.cn/problem-sets/994805260223102976/problems/1038429065476579328 做作业的时候,邻座的小盆友问你:“五乘以七 ...
- Spring 集成Quartz
在使用jdk的timer时发现无法在指定的日期进行执行任务.这便引入一个优秀的开源任务调度框架“quartz”.这里使用的是quartz-1.8.6版本.Quart的官网:http://www.qua ...
- [CF895C]Square Subsets
题目大意:给一个集合$S$($1\leq S_i\leq 70$),选择一个非空子集,使它们的乘积等于某个整数的平方的方法的数量. 求方案数,若两种方法选择的元素的索引不同,则认为是不同的方法. 题解 ...
- [LeetCode] decode ways 解码方式
A message containing letters fromA-Zis being encoded to numbers using the following mapping: 'A' -&g ...
- BZOJ4550 小奇的博弈 【Nimk游戏 + dp + 组合数】
题目 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色.最左边是白色棋子,最右边 是黑色棋子,相邻的棋子颜色不同. 小奇可以移动白色棋子,提比可以移动黑色的棋子,它们每次 ...
- 【BZOJ 4103】 [Thu Summer Camp 2015]异或运算 可持久化01Trie
我们观察数据:树套树 PASS 主席树 PASS 一层一个Trie PASS 再看,异或!我们就把目光暂时定在01Tire然后我们发现,我们可以带着一堆点在01Trie上行走,因为O(n*q* ...
- git使用笔记(七)版本回退和撤销
By francis_hao Nov 21,2016 从版本库初始化开始,每一步的撤销操作 添加第一个文件 在空的版本库中创建了一个文件并git add到了缓存区,这时候怎么撤销呢? 撤销单个文 ...
- oracle获取主机服务器IP
--要获取服务器端的IP :: SYS@XXX> select utl_inaddr.get_host_address from dual; GET_HOST_ADDRESS --------- ...
- 设备VMnet0上的网络桥接当前未在运行解决办法
问题: 今天把自己的VM从C盘挪到了D盘,然后再open所有VM都会显示网卡无法桥接了 “vmware 没有未桥接的主机网络适配器” 解决办法: 1.关闭所有VM 2.打开 编辑-虚拟网络编辑器,会发 ...