关于 Delphi 参数传递方式的一点研究

原创 2004年08月27日 23:41:00
某次看 D6DG 说默认的参数传递方式因为会为变量产生本地副本所以会消耗额外的内存,而 const 方式会优化字符串和记录类型的参数传递时的内存占用。从而猜测 const 方式的参数传递实际也是按地址传递,只是编译器强制不允许函数内的代码修改 const 方式传递进去的变量而已。
为了证实我的猜想,特设计以下实验,本实验中使用到了字符串(本文提到的字符串都是指 Delphi 默认的字符串 AnsiString)内部结构中的引用计数。
关于字符串的引用计数,结合 D6DG 中的说明和偶的实际研究,得出的结论是,字符串地址实际上是其内容的第一个字符的地址,在此地址之前的 12 字节内存中的内容才是字符串内部结构中的头部,分别是 32 位字符串占用的内容空间大小,32 位引用计数,32 位字符串长度(仅在 Delphi 7 中验证,推测 Delphi 7 以前的 32 位 Delphi 中的字符串结构都应该是这样,未验证)。


以下代码中 sGlobal 为全局字符串变量。





在主程序里分别以初始化后的 sGlobal 为实参调用这几个过程后,我们会看到三种方式 S 的地址都跟 sGlobal 的一样,这初步说明 var 方式和 const 方式确实都是按地址传递参数。
但不可思议的是,默认参数传递方式不会是为变量产生本地副本吗?为什么 S 的地址还会跟 sGlobal 一样呢?因为一开始我设计这个实验时并没有添加显示引用计数的代码,所以很是迷茫。之后想起了 Borland 使用了引用计数的方式和 copy-on-write 技术(对于字符串等使用这两个技术的数据类型的变量 A、B,将 A 赋值给 B 时实际上只是赋值 A 的地址给 B,并增加 A 的引用计数,直到两者其中一个被修改时才为 B 申请新的内存空间并且复制 A 的内容,同时减少 A 的引用计数)来优化字符串的操作。于是查阅 D6DG 并且观察 Delphi 的汇编代码和内存(在 CPU 窗口中)得出了本文开头关于字符串引用计数的结论。
这样,添加了显示引用计数的代码之后我们就可以观察到,使用默认方式时 S 和 sGlobal 的引用计数,都是 2,而其他方式时两者的引用计数都是 1,这更有力的说明了 const 方式确实是按地址传递,而不是像默认方式那样只是增加引用计数。这样,当我们把第一个过程中第一行代码的注释去掉后再次运行程序,可以看到默认方式时 S 的地址已经跟 sGlobal 不同了,同时两者的引用计数都是 1 了,说明确实是在 S 被修改后才产生本地副本(copy-on-write)。

那么,现在我们知道参数类型为字符串时, const 方式的参数传递实际是传递参数地址,这可以优化内存的使用,而参数为其他数据类型时是不是这样呢?
为此修改刚才的程序如下,其中 iGlobal 为全局整形变量。


procedure Method1(I: Integer);
begin
Form1.Memo1.Lines.Add('I 地址: ' + IntToStr(Integer(@I)));
Form1.Memo1.Lines.Add('');
end;

procedure Method2(var I: Integer);
begin
Form1.Memo1.Lines.Add('I 地址: ' + IntToStr(Integer(@I)));
Form1.Memo1.Lines.Add('');
end;

procedure Method3(const I: Integer);
begin
Form1.Memo1.Lines.Add('I 地址: ' + IntToStr(Integer(@I)));
Form1.Memo1.Lines.Add('');
end;

procedure iGlobalInfo;
begin
Form1.Memo1.Lines.Add('iGlobal 地址: ' + IntToStr(Integer(@iGlobal)));
Form1.Memo1.Lines.Add('');
end;

在主程序里分别以初始化后的 iGlobal 为实参调用这个过程后,可以看到只有 var 方式中 I 的地址跟 iGlobal 一样,而默认方式和 const 都会为 iGlobal 产生本地副本,可见确实如 D6DG 所说 const 会(也只会)优化字符串和记录类型的参数传递时的内存占用。

至此实验目的达到,还附带了解了 string 的内部格式。

附上实验程序源代码。
点击下载

数据以报表形式展现的实现方法研究

背景:系统的信息业务数据往往我们需要将其显示出来,通常我们用的方式是利用报表的形式将数据打印出来,这样的好处是可以生成形式多样的格式例如pdf,html等等,但是我们也可以使用htp的形式将数据打印出...
  • caixingyun
  • caixingyun
  • 2013年12月14日 11:20
  • 1986

研究生如何看论文?

期间的研究生是很重要的功课,不可忽视,这种能力是需要训练的。关于做读书和文献阅读笔记,这里谈点个人的看法,算是跟年轻朋友们的交流,也希望得到专家们的指教。 如何选择和阅读文献?阅读文献,要力求对一个方...
  • u012116229
  • u012116229
  • 2015年03月05日 12:11
  • 392

delphi 如何判断编码格式,解决乱码问题

前阵子因为需要用到idhttp下载网页,然而令人很生气的是,他下载的html源码是乱码的,这样子是没有办法使用的,所以就必须要把他进行编码格式转换,然而令人困扰的是,他是什么格式,又该怎么转,转成什么...
  • u014028956
  • u014028956
  • 2016年01月24日 15:56
  • 3706

JMX的一点研究

JMX学习总结 前段时间研究tomcat,发现里面涉及到了好多JMX的内容,那么抽点时间学习研究了一下,总结如下: 1.JMX是什么? JMX(java ManagementExtensions...
  • lantian0802
  • lantian0802
  • 2013年03月24日 17:17
  • 1203

关于以太网PAUSE的一点研究

在学习自动协商时,发现有以太网PAUSE帧这个东西,很网上资料很少,有讲到的也是很简略,似乎这是一个神秘的不想让人知道的东西。这里将自己对PAUSE帧的一些研究,对于太术语的方面,直接参考网上资料,不...
  • subfate
  • subfate
  • 2015年04月11日 20:10
  • 4057

卷积地图的一点研究

假设游戏设定如下:   玩家沿着2d横版地图在走,走到屏幕的某一点后,玩家虽然在做走的动作,但是实际上是地图在向后走,而玩家不动,以此来保持玩家的视野。 玩家从左向右向右的过程,可以分为以下几个...
  • dayday_up2
  • dayday_up2
  • 2015年03月12日 11:40
  • 390

关于KMP算法的一点研究

KMP
  • govshell
  • govshell
  • 2017年02月15日 11:59
  • 104

关于C#中readonly的一点小研究

可能园子里有不少文章已经说明了这个问题了,但是我在这里写这篇博客只是写写自己的一些体会,也权当是整理归纳,高手莫见笑。 ===============正文分割线=================...
  • linshichen
  • linshichen
  • 2017年05月24日 10:05
  • 103

HWM的一点研究

今天一位同事发现11g环境中一张实验数据表筛选变得很慢,即使为空表。通过EM观察,发现指定sql语句等待时间和执行时间都很长(达到秒级)。   经过进一步询问,确定该表曾经进行批量数据DML操作,...
  • xiaoxing1521025
  • xiaoxing1521025
  • 2013年11月27日 12:24
  • 419

String和StringBuffer的一点研究

转载自:http://www.cnblogs.com/heshan664754022/archive/2013/03/15/2961463.html 首先请看下下面的这几个输出的结果...
  • xiong_mao_1
  • xiong_mao_1
  • 2014年03月07日 23:08
  • 785
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:关于 Delphi 参数传递方式的一点研究
举报原因:
原因补充:

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