ImageVerifierCode 换一换
格式:DOC , 页数:7 ,大小:49.50KB ,
资源ID:8044098      下载积分:10 金币
快捷注册下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

开通VIP
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.zixin.com.cn/docdown/8044098.html】到电脑端继续下载(重复下载【60天内】不扣币)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

开通VIP折扣优惠下载文档

            查看会员权益                  [ 下载后找不到文档?]

填表反馈(24小时):  下载求助     关注领币    退款申请

开具发票请登录PC端进行申请

   平台协调中心        【在线客服】        免费申请共赢上传

权利声明

1、咨信平台为文档C2C交易模式,即用户上传的文档直接被用户下载,收益归上传人(含作者)所有;本站仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。所展示的作品文档包括内容和图片全部来源于网络用户和作者上传投稿,我们不确定上传用户享有完全著作权,根据《信息网络传播权保护条例》,如果侵犯了您的版权、权益或隐私,请联系我们,核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
2、文档的总页数、文档格式和文档大小以系统显示为准(内容中显示的页数不一定正确),网站客服只以系统显示的页数、文件格式、文档大小作为仲裁依据,个别因单元格分列造成显示页码不一将协商解决,平台无法对文档的真实性、完整性、权威性、准确性、专业性及其观点立场做任何保证或承诺,下载前须认真查看,确认无误后再购买,务必慎重购买;若有违法违纪将进行移交司法处理,若涉侵权平台将进行基本处罚并下架。
3、本站所有内容均由用户上传,付费前请自行鉴别,如您付费,意味着您已接受本站规则且自行承担风险,本站不进行额外附加服务,虚拟产品一经售出概不退款(未进行购买下载可退充值款),文档一经付费(服务费)、不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
4、如你看到网页展示的文档有www.zixin.com.cn水印,是因预览和防盗链等技术需要对页面进行转换压缩成图而已,我们并不对上传的文档进行任何编辑或修改,文档下载后都不会有水印标识(原文档上传前个别存留的除外),下载后原文更清晰;试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓;PPT和DOC文档可被视为“模板”,允许上传人保留章节、目录结构的情况下删减部份的内容;PDF文档不管是原文档转换或图片扫描而得,本站不作要求视为允许,下载前可先查看【教您几个在下载文档中可以更好的避免被坑】。
5、本文档所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用;网站提供的党政主题相关内容(国旗、国徽、党徽--等)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
6、文档遇到问题,请及时联系平台进行协调解决,联系【微信客服】、【QQ客服】,若有其他问题请点击或扫码反馈【服务填表】;文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“【版权申诉】”,意见反馈和侵权处理邮箱:1219186828@qq.com;也可以拔打客服电话:0574-28810668;投诉电话:18658249818。

注意事项

本文(delphi中堆和栈的区别.doc)为本站上传会员【s4****5z】主动上传,咨信网仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知咨信网(发送邮件至1219186828@qq.com、拔打电话4009-655-100或【 微信客服】、【 QQ客服】),核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载【60天内】不扣币。 服务填表

delphi中堆和栈的区别.doc

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存放栈底指

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

4、cx, FS:[4]; //FS:[4]放置发生异常时的栈信息 sub ecx, 3; mov [eax], eax; //栈顶,eax接收第一个参数 mov [edx], ebp; //栈低,edx接收第二个参数 end; end; 知道了栈的首尾地址之后,我们就可以取出变量地址,然后和栈的地址比较,如果超出栈的范围,则表示变量在堆中。 2.3.2基本数据类型:函数体中->栈;类中->堆 基本数据类型(Integer、Cardinal、Shortint、Smallint、Longint、Int64、Byte、Word、LongWord、Char)在函数体内分配

5、是在栈中的,如果在类中分配则是在堆中的。另外Int64也是在栈中分配的,它具体的分配是偏移8字节。我们写下如下测试代码: procedure TestInt64; var Value: Int64; StackTop, StackBottom: Cardinal; begin Value := 10; GetStackAddress(StackTop, StackBottom); ShowMessage(Format('StackTop: %s, StackBottom: %s; Int64 Address: %s', [IntToHex(StackT

6、op, 8), IntToHex(StackBottom, 8), IntToHex(Integer(@Value), 8)])); end; 我电脑测试显示的信息为StackTop: 0012F5E0, StackBottom: 0012F628; Int64 Address: 0012F620,从上面信息我们可以看出栈底偏8字节就是Value的地址。 2.3.3 指针类型:指针->栈,指针的内容->堆 指针在函数体内分配,指针的地址是在栈中的,指针的内容是在堆中的。指针如果在类中分配则,指针地址和指针内容都是在堆中的。我们写下如下测试代码: procedure TestPoint

7、er; var APoint: Pointer; StackTop, StackBottom: Cardinal; begin GetMem(APoint, 1000); GetStackAddress(StackTop, StackBottom); ShowMessage(Format('StackTop: %s, StackBottom: %s; Pointer Address: %s; Pointer Content Address: %s', [IntToHex(StackTop, 8), IntToHex(StackBottom, 8), In

8、tToHex(Integer(@APoint), 8), IntToHex(Integer(APoint), 8)])); end; 我的电脑测试显示的信息为StackTop: 0012F568, StackBottom: 0012F5B8; Pointer Address: 0012F5B4; Pointer Content Address: 00A3FD10,从上面的信息我们可以栈底偏4字节就是指针的地址。 2.3.4 固定数组:函数体中->栈;类中->堆 固定数组在函数体内分配是在栈中的,如果在类中分配则是在堆中的。因此不能函数体内分配超过1M大小的固定数组,否则会造成栈溢

9、出。我们写下如下测试代码: type TFixArray = array[0..9] of Integer; procedure TestFixArray; var FixArray: TFixArray; StackTop, StackBottom: Cardinal; begin FixArray[0] := 10; GetStackAddress(StackTop, StackBottom); ShowMessage(Format('StackTop: %s, StackBottom: %s; Int64 Address: %s', [I

10、ntToHex(StackTop, 8), IntToHex(StackBottom, 8), IntToHex(Integer(@FixArray[0]), 8)])); end; 我的电脑测试显示的信息为StackTop: 0012F550, StackBottom: 0012F5B8; Fix Array Address: 0012F588,从上面的信息我们可以看出固定数组是在栈中的,动态数组类似指针,只是动态数组的指针在栈中,动态数组的内容是在堆中的。另外我们从汇编代码也可以看出相同的信息,FixArray[0] := 10对应的汇编代码是mov [ebp-$30],$000000

11、0a,ebp指向栈底,因此我们可以看出动态数组的内存是在栈中的。 2.3.5 结构体:函数体中->栈;类中->堆 结构体在函数体内分配是在栈中的,在类中分配则是在堆中的,如果结构体内含有string等指针类型,则指针的地址在栈内,指针的内容是在堆中的。在函数体内分配超过1M大小的结构体也会造成栈溢出。我们写下如下测试代码: type TRecord = record Value: string; Len: Integer; end; procedure TestRecord; var PntRecord: TRecord; StackTop, St

12、ackBottom: 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(@PntRecord), 8), IntToH

13、ex(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、动态数组的内容都是在堆中的,下面我

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

15、f 0: (Reserved2, Reserved3: Word; case Integer of varSmallInt: (VSmallInt: SmallInt); varInteger: (VInteger: Integer); varSingle: (VSingle: Single); varDouble: (VDouble: Double); varCurrency: (VCurrency: Currency); varDate: (VDate: TDateTime); varOleStr: (VOleStr: PWideCha

16、r); varDispatch: (VDispatch: Pointer); varError: (VError: HRESULT); varBoolean: (VBoolean: WordBool); varUnknown: (VUnknown: Pointer); varShortInt: (VShortInt: ShortInt); varByte: (VByte: Byte); varWord: (VWord: Word); varLongWord: (VLongWord: LongWord); varInt64: (VInt64:

17、 Int64); varString: (VString: Pointer); varAny: (VAny: Pointer); varArray: (VArray: PVarArray); varByRef: (VPointer: Pointer); ); 1: (VLongs: array[0..2] of LongInt); ); 2: (VWords: array [0..6] of Word); 3: (VBytes: array [0..13] of Byte); ); 1: (RawData: array [0..

18、3] of LongInt); end; 从定义中我们可以看出varOleStr、varString、varArray、varByRef都是在堆中的。 2.5 全局变量在堆中 全局变量的指针地址和指针内容都是在栈中的,我们把他归类到堆中。 2.6 栈和堆比较 2.6.1 栈和堆的管理方式比较 栈:由操作系统自动分配,而且在栈上分配内存是由编译器自动完成的,栈不需要编译器管理,操作系统自动实现申请释放; 堆:由操作系统提供接口,各个编译器实现管理方式,由外部程序申请释放,如果外部程序在程序结束时没有释放,由操作系统强行释放,在DELPHI中是用GetMem.inc来实现内

19、存管理; 2.6.2 栈和堆的初始化比较 栈:分配的内存不会初始化,是一个垃圾值; 堆:分配的内存不会初始化,是一个垃圾值,但是DELPHI默认初始化类变量和全局变量; 2.6.3 栈和堆的申请方式比较 栈:由系统自动分配,如在函数申明一个局部变量i: Integer;编译器会自动在栈中分配内存; 堆:由程序自己管理,需要程序员自己申请,并指明大小; 2.6.4 堆和栈的效率比较 栈:在栈上分配空间是直接用add指令,对esp进行移位,例如add esp,-$44,可以在一个指令周期内完成; 堆:操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历

20、该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样代码中的FreeMem语句才能正确的释放本内存空间。 另外由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。 在堆中分配内存的时候会用HeapLock和HeapUnlock加锁,因此在多线程中分配内存是线性的,效率低下; 2.6.5 栈和堆的大小限制比较 栈:在Windows下栈默认大小是1M, 栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶

21、的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是固定的(是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。 堆:在Windows下默认堆大小是2GB,堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。 2.6.6 栈和堆的超出范围比较 栈:超出栈大小会报栈溢出,提示overflow; 堆:超出堆大小会报Out Of M

22、emory; 原帖地址: 2.7 总结(zwh) 1、 基本数据类型变量和指针本身:局部变量在栈中,全局变量、类变量在堆中。 2、 指针指向的内容、动态数组、字符串类型(String、ShortString、WideString)、变体类型(Variant、OleVariant):不管局部变量还是全局变量、类变量都在堆中。 3、 DELPHI默认初始化堆中的变量; 2.8 线程中的堆栈(zwh) 1、 在一个进程的线程共享堆区,而进程中的线程各自维持自己栈。(C、Java也适用) 2、 也就是说,线程中,栈是私有的但堆是公用的。(C、Java也适用) 3、 因为栈是私有的但堆是公用的, 如果不同的线程都来使用一个全局变量有点乱套。为解决这个问题 Delphi 为我们提供了一个类似 var 的 ThreadVar 关键字, 线程在使用 ThreadVar 声明的全局变量时会在各自的栈中留一个副本, 这样就解决了冲突. 不过还是尽量使用局部变量, 或者在继承TThread 时使用类的成员变量, 因为 ThreadVar 的效率不好, 据说比局部变量能慢 10 倍.

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服