来自:http://blog.sina.com.cn/s/blog_4bc47d2301018trf.html

------------------------------------------------------------------

delphi dispose释放内存的方法 New  GetMem 的区别

定义一个record 类型,经过多次new dispose后,从windows任务管理器看,占用的内存比启动时大了很多,似乎越来越大

设置 ReportMemoryLeaksOnShutdown := true; 再运行,仍然没有提示 memory leak。

其实就是dispose 本身的原因。

delphi设计的 dispose 释放内存时,只是标记这部分内存可以再用来被 new 等函数分配,并不是把从系统申请到的内存归还给操作系统,只在程序结束时,才全部释放给操作系统。

比如 new 申请 15 个记录(sizeof=64字节) 的空间,然后 dispose 释放。再使用 new 申请 10个,此时这 10 个就不再请求系统了,直接从刚才的 15个 (此时已经空闲) 中分10 个出来。只有在占用的空闲内存不够使用时,才请求操作系统分配内存(剩余部分)。

若前一次15个空间地址如左列,释放后,下一次10个空间的地址如右列,即从前次分配的最后一个地址开始,按前次的顺序,倒过来分配10个。

00F23860
00F23818
00F237D0
00F23788
00F23740
00F236F8
00F236B0
00F23668
00F23620
00F235D8
00F23590
00F23548
00F23500
00F234B8
00F23470

00F23470
00F234B8
00F23500
00F23548
00F23590
00F235D8
00F23620
00F23668
00F236B0
00F236F8

如果操作一个 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.

===================================================
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 给了我们充分的自由,试用范围更广。当然,具体选用哪个,还要看实际情况而定。

delphi dispose释放内存的方法 New 和 GetMem 的区别的更多相关文章

  1. delphi dispose释放内存的方法

    delphi dispose释放内存的方法 2010-06-08 19:39:59|  分类: DELPHI |  标签: |举报 |字号大中小 订阅     dispose使用方法的简单介绍在本文末 ...

  2. Delphi EurekaLog 调试内存泄露方法

    要使用EurekaLog进行内存泄露检测,需要手动开启"EurekaLog Options..."下的"Advanced Options"旁的"Mem ...

  3. Java Map释放内存置null以及调用clear()的区别

    今天自己在总结map的时候,想到了在释放Map对象空间的时候就有使用过将Map对象置null,也有时候会调用clear()将Map中的数据清除,那么它们都有什么区别呢? Map<Integer, ...

  4. CentOS/Linux内存占用大,用Shell脚本自动定时清除/释放内存

    CentOS/Linux内存占用大,用Shell脚本自动定时清除/释放内存来自:互联网 时间:2020-03-22 阅读:114以下情况可能造成Linux内存占用过高服务配置存在直接分配错误,或隐性分 ...

  5. Delphi动态创建组件,并释放内存

    开发所用delphi版本是xe2,效果图如下: 代码如下: ---------------------------------------------------------------------- ...

  6. vector释放内存之swap方法

    相信大家看到swap这个词都一定不会感到陌生,就是简单的元素交换.但swap在C++ STL中散发着无穷的魅力.下面将详细的说明泛型算法swap和容器中的swap成员函数的使用! 1. 泛型算法swa ...

  7. linux 手工释放内存 高内存 内存回收 方法思路

    linux  跑的apache,apache工作模式有   Prefork.Worker和 Event  三种,分别是基于进程.线程.综合模式.        本文中使用的apache是 Event  ...

  8. CentOS7清理yum缓存和释放内存方法

    清理yum缓存 清理yum缓存使用yum clean 命令,yum clean 的参数有headers, packages, metadata, dbcache, plugins, expire-ca ...

  9. C# winform在关闭窗体的时候及时释放内存问题

    winform中如果每次打开的窗体都是通过new出来的,发现几次过后就会出现提示”内存不足“问题,那么在关闭窗体的时候怎么处理可以及时释放内存?dispose方法可能也无法解决这个问题.我们可以每次在 ...

随机推荐

  1. BZOJ 3925 ZJOI2015 地震后的幻想乡 状压dp+期望

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3925 题意概述: 给出一张N点M边的最小生成树,其中每条边的长度为[0,1]的实数,求最小 ...

  2. UVA 1085 House of Cards(对抗搜索)

    Description   Axel and Birgit like to play a card game in which they build a house of cards, gaining ...

  3. Week1 Team Homework #1 from Z.XML-对于学长项目《shield star》的思考和看法

    试用了一下学长黄杨等人开发的<shield star>游戏.                      其实作为一个学弟,我对cocos2d-x引擎还算是比较了解,所以对于这样一款很“典型 ...

  4. chromium源码阅读--图片处理

    JavaScript 图像替换 JavaScript 图像替换技术检查设备能力,然后“做正确的事”. 您可以通过 window.devicePixelRatio 确定设备像素比,获取屏幕的宽度和高度, ...

  5. java计算两个日期之间的相隔天数

    [原创] 之前在很多竞赛的题目中有这样饿一类题,计算给定两个日期之间的相隔天数,或者很多类似的题目,都是需要转化到这个问题上时,之前用c++写的时候思想是这样的,一个结构体,包括年月日,还有一个计算下 ...

  6. PowerDesigner工具箱(palette)关了如何重新打开

    PowerDesigner的设计工具箱palette,palette的实际意思:颜料.调色板 工具箱关闭了 重新打开的方法其实很简单的,贴几张图片上来,帮助一下大家 方法一: 在工具栏的空白处点击鼠标 ...

  7. QT启动一个工程

    功能描述: 模拟如下页面. 当输入一个字符串时打开对应的应用程序. 实现方法: 1. 建立工程 2. 界面编辑: 3. 在test1.h中添加slot声明 4. test1.cpp中添加slot定义 ...

  8. kafka卡顿

    一次kafka卡顿事故排查过程 https://www.cnblogs.com/yougewe/p/8975550.html 由于一次功能上线后,导致某数据量急剧下滑,给我们紧张的呢!排查过程也是个学 ...

  9. 机器学习基础知识笔记(一)-- 极大似然估计、高斯混合模型与EM算法

    似然函数 常说的概率是指给定参数后,预测即将发生的事件的可能性.拿硬币这个例子来说,我们已知一枚均匀硬币的正反面概率分别是0.5,要预测抛两次硬币,硬币都朝上的概率: H代表Head,表示头朝上 p( ...

  10. PyQt5学习--基本窗口控件--QMainWindow

    QMainWindow主窗口为用户提供一个应用程序框架,它有自己的布局,可以在布局中添加控件.比如将工具栏.菜单栏和状态栏等添加到布局管理器中. 窗口类型介绍 QMainWindow.QWidget和 ...