delphi中堆和栈的区别

上传人:宝路 文档编号:20906904 上传时间:2017-11-22 格式:DOC 页数:7 大小:49.85KB
返回 下载 相关 举报
delphi中堆和栈的区别_第1页
第1页 / 共7页
delphi中堆和栈的区别_第2页
第2页 / 共7页
delphi中堆和栈的区别_第3页
第3页 / 共7页
delphi中堆和栈的区别_第4页
第4页 / 共7页
delphi中堆和栈的区别_第5页
第5页 / 共7页
点击查看更多>>
资源描述

《delphi中堆和栈的区别》由会员分享,可在线阅读,更多相关《delphi中堆和栈的区别(7页珍藏版)》请在金锄头文库上搜索。

1、delphi 堆和栈 转2.1 栈栈是由操作系统在创建线程的时候,系统自动创建,栈是由顶像下分配的,DELPHI 中默认的栈大小是 1M,这个可以通过 Project-Options-Linker-Max Stack size 来改变其大小。栈是线程执行代码的地方,操作系统根据系统调度算法来加载执行的代码,另外栈还存放函数的参数值,局部变量。栈的存取是按 4 字节偏移,不会根据需要动态增长,因此超出范围会报栈溢出。2.2 堆我们把在栈之外的分配内存都叫在堆上分配内存,堆是由程序员分配释放。在 DELPHI 中是用 GetMem.inc 中的代码来管理堆的,堆中包含许多大小不确定的块。初始状态下

2、,堆仅有一个块,即堆本身。经过一段时间地取用和回收以后,堆中将可能只剩下一些“切割”后残余的“碎片” ,且这些碎片可能已经无法再合并。此时,如果一个新的请求大于任何一个碎片,那么就必须再申请一个新的、大的块放在堆中。堆的使用永远是一个“拆东墙补西墙”的过程。堆的大小是 2G,在扩展内存模式下能达到 3G。注意它与数据结构中的堆是两回事,它的分配方式类似于链表,访问“堆”的内容的时候需要先找到这个“堆” ,然后再遍历链表,因此“堆”访问会比“栈”慢。2.3 哪些在栈中2.3.1 获取栈的首尾地址获取通常情况下的栈地址在写汇编的时候,我们知道 esp 存放栈顶指针,ebp 存放栈底指针proced

3、ure GetStackAddress(var AStackTop, AStackBottom: Cardinal);beginasmmov eax, esp; /栈顶,eax 接收第一个参数mov edx, ebp; /栈底,edx 接收第二个参数end;end;获取异常发生时的栈地址在 Windows 下,FS:4存放发生异常时的栈顶指针。procedure GetStackAddress(var AStackTop, AStackBottom: Cardinal);begin asmmov ecx, FS:4; /FS:4放置发生异常时的栈信息sub ecx, 3;mov eax, ea

4、x; /栈顶,eax 接收第一个参数mov edx, ebp; /栈低,edx 接收第二个参数end;end;知道了栈的首尾地址之后,我们就可以取出变量地址,然后和栈的地址比较,如果超出栈的范围,则表示变量在堆中。2.3.2 基本数据类型:函数体中-栈;类中-堆基本数据类型(Integer 、Cardinal、Shortint、Smallint、Longint、Int64、Byte、Word、LongWord、Char)在函数体内分配是在栈中的,如果在类中分配则是在堆中的。另外 Int64 也是在栈中分配的,它具体的分配是偏移 8 字节。我们写下如下测试代码:procedure TestInt

5、64;varValue: Int64;StackTop, StackBottom: Cardinal;beginValue := 10;GetStackAddress(StackTop, StackBottom);ShowMessage(Format(StackTop: %s, StackBottom: %s; Int64 Address: %s,IntToHex(StackTop, 8), IntToHex(StackBottom, 8), IntToHex(Integer(Value), 8);end;我电脑测试显示的信息为 StackTop: 0012F5E0, StackBottom:

6、 0012F628; Int64 Address: 0012F620,从上面信息我们可以看出栈底偏 8 字节就是 Value 的地址。2.3.3 指针类型:指针-栈,指针的内容-堆指针在函数体内分配,指针的地址是在栈中的,指针的内容是在堆中的。指针如果在类中分配则,指针地址和指针内容都是在堆中的。我们写下如下测试代码:procedure TestPointer;varAPoint: Pointer;StackTop, StackBottom: Cardinal;beginGetMem(APoint, 1000);GetStackAddress(StackTop, StackBottom);Sh

7、owMessage(Format(StackTop: %s, StackBottom: %s; Pointer Address: %s; Pointer Content Address: %s,IntToHex(StackTop, 8), IntToHex(StackBottom, 8), IntToHex(Integer(APoint), 8), IntToHex(Integer(APoint), 8);end;我的电脑测试显示的信息为 StackTop: 0012F568, StackBottom: 0012F5B8; Pointer Address: 0012F5B4; Pointer

8、Content Address: 00A3FD10,从上面的信息我们可以栈底偏 4 字节就是指针的地址。2.3.4 固定数组:函数体中-栈;类中-堆固定数组在函数体内分配是在栈中的,如果在类中分配则是在堆中的。因此不能函数体内分配超过 1M 大小的固定数组,否则会造成栈溢出。我们写下如下测试代码:typeTFixArray = array0.9 of Integer;procedure TestFixArray;varFixArray: TFixArray;StackTop, StackBottom: Cardinal;beginFixArray0 := 10;GetStackAddress(

9、StackTop, StackBottom);ShowMessage(Format(StackTop: %s, StackBottom: %s; Int64 Address: %s,IntToHex(StackTop, 8), IntToHex(StackBottom, 8), IntToHex(Integer(FixArray0), 8);end;我的电脑测试显示的信息为 StackTop: 0012F550, StackBottom: 0012F5B8; Fix Array Address: 0012F588,从上面的信息我们可以看出固定数组是在栈中的,动态数组类似指针,只是动态数组的指针

10、在栈中,动态数组的内容是在堆中的。另外我们从汇编代码也可以看出相同的信息,FixArray0 := 10 对应的汇编代码是 mov ebp-$30,$0000000a,ebp 指向栈底,因此我们可以看出动态数组的内存是在栈中的。2.3.5 结构体:函数体中-栈;类中-堆结构体在函数体内分配是在栈中的,在类中分配则是在堆中的,如果结构体内含有 string等指针类型,则指针的地址在栈内,指针的内容是在堆中的。在函数体内分配超过 1M 大小的结构体也会造成栈溢出。我们写下如下测试代码:typeTRecord = recordValue: string;Len: Integer;end;proced

11、ure TestRecord;varPntRecord: TRecord;StackTop, StackBottom: Cardinal;begin PntRecord.Value := Test;GetStackAddress(StackTop, StackBottom);ShowMessage(Format(StackTop: %s, StackBottom: %s; Record Address: %s; Record Pointer Address: %s,IntToHex(StackTop, 8), IntToHex(StackBottom, 8), IntToHex(Integer

12、(PntRecord), 8),IntToHex(Integer(PChar(PntRecord.Value), 8);end;我的电脑测试显示的信息为 StackTop: 0012F564, StackBottom: 0012F5B8; Record Address: 0012F5B0; Record Pointer Address: 0045F4B4,从上面的信息我们可以看出结构体是在栈中的,结构体指针和指针一样。2.4 哪些在堆中用内存申请函数申请的内存都是在堆中的,如用New、GetMem 、StrAlloc、AllocMem、SysGetMem,哪些自管理类型 string、动态数组

13、的内容都是在堆中的,下面我们给出结论,测试代码大家可以仿照上面的判断变量是否在栈中的代码编写。2.4.1 指针指向的内容是在堆中2.4.2 动态数组的内容是在堆中2.4.3 String、ShortString 、WideString 的内容是在堆中2.4.4 变体 Variant、OleVariant 的内容是在堆中变体类型是一个结构体,它的定义是:TVarData = packed recordcase Integer of0: (VType: TVarType;case Integer of0: (Reserved1: Word;case Integer of0: (Reserved2,

14、 Reserved3: Word;case Integer ofvarSmallInt: (VSmallInt: SmallInt);varInteger: (VInteger: Integer);varSingle: (VSingle: Single);varDouble: (VDouble: Double);varCurrency: (VCurrency: Currency); varDate: (VDate: TDateTime);varOleStr: (VOleStr: PWideChar);varDispatch: (VDispatch: Pointer);varError: (VE

15、rror: HRESULT);varBoolean: (VBoolean: WordBool);varUnknown: (VUnknown: Pointer);varShortInt: (VShortInt: ShortInt);varByte: (VByte: Byte);varWord: (VWord: Word);varLongWord: (VLongWord: LongWord);varInt64: (VInt64: Int64);varString: (VString: Pointer);varAny: (VAny: Pointer);varArray: (VArray: PVarA

16、rray);varByRef: (VPointer: Pointer););1: (VLongs: array0.2 of LongInt););2: (VWords: array 0.6 of Word);3: (VBytes: array 0.13 of Byte););1: (RawData: array 0.3 of LongInt);end;从定义中我们可以看出 varOleStr、varString、varArray、varByRef 都是在堆中的。2.5 全局变量在堆中全局变量的指针地址和指针内容都是在栈中的,我们把他归类到堆中。2.6 栈和堆比较2.6.1 栈和堆的管理方式比较栈:由操作系统自动分配,而且在栈上分配内存是由编译器自动完成的,栈不需要编译器管理,操作系统自动实现申请释放;堆:由操作系统提供接口,各个编译器实现管理方式,由外部程序申请释放,如

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 行业资料 > 其它行业文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号