专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »C 教程 » 未结束的字符串常量:C++堆、栈、自由存储区、全局/静态存储区和常量存储区 »正文

未结束的字符串常量:C++堆、栈、自由存储区、全局/静态存储区和常量存储区

来源: 发布时间:星期四, 2009年2月12日 浏览:85次 评论:0


在C内存分成5个区他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区
就是那些由编译器在需要时候分配在不需要时候自动清楚变量存储区里面变量通常是局部变量、参数等
就是那些由分配内存块他们释放编译器不去管由我们应用去控制就要对应个delete如果员没有释放掉那么在结束后操作系统会自动回收
自由存储区就是那些由malloc等分配内存块他和堆是十分相似不过它是用free来结束自己生命
全局/静态存储区全局变量和静态变量被分配到同块内存中在以前C语言中全局变量又分为和未在C里面没有这个区分了他们共同占用同块内存区
常量存储区这是块比较特殊存储区他们里面存放是常量不允许修改(当然你要通过非正当手段也可以修改而且思路方法很多)
明确区分堆和栈
在bbs上堆和栈区分问题似乎是个永恒话题由此可见初学者对此往往是混淆不清所以我决定拿他第个开刀
首先我们举个例子:
void f { * p= [5]; }
这条短短句话就包含了堆和栈看到我们首先就应该想到我们分配了块堆内存那么指针p呢?他分配块栈内存所以这句话意思就是: 在栈内存中存放了个指向块堆内存指针p会先确定在堆中分配内存大小然后operator 分配内存然后返回这块内存首地址放入栈中他在VC6下汇编代码如下:
00401028 push 14h
0040102A call operator (00401060)
0040102F add esp,4
00401032 mov dword ptr [ebp-8],eax
00401035 mov eax,dword ptr [ebp-8]
00401038 mov dword ptr [ebp-4],eax
这里我们为了简单并没有释放内存那么该如何去释放呢?是delete p么?澳错了应该是delete p这是为了告诉编译器:我删除VC6就会根据相应Cookie信息去进行释放内存工作
好了我们回到我们主题:堆和栈究竟有什么区别?
主要区别由以下几点:
1、管理方式区别;
2、空间大小区别;
3、能否产生碎片区别;
4、生长方向区别;
5、分配方式区别;
6、分配效率区别;
管理方式:对于栈来讲是由编译器自动管理无需我们手工控制;对于堆来说释放工作由员控制容易产生memory leak[Page]
空间大小:般来讲在32位系统下堆内存可以达到4G空间从这个角度来看堆内存几乎是没有什么限制但是对于栈来讲般都是有空间大小例如在VC6下面默认栈空间大小是1M(好像是记不清楚了)当然我们可以修改:
打开工程依次操作菜单如下:Project->Setting->Link在Category 中选中Output然后在Reserve中设定堆栈最大值和commit
注意:reserve最小值为4Byte;commit是保留在虚拟内存页文件里面它设置较大会使栈开辟较大可能增加内存开销和启动时间
碎片问题:对于堆来讲频繁/delete势必会造成内存空间不连续从而造成大量碎片使效率降低对于栈来讲则不会存在这个问题 栈是先进后出队列他们是如此对应以至于永远都不可能有个内存块从栈中间弹出在他弹出的前在他上面后进栈内容已经被弹出详细 可以参考数据结构这里我们就不再讨论了
生长方向:对于堆来讲生长方向是向上也就是向着内存地址增加方向;对于栈来讲生长方向是向下是向着内存地址减小方向增长
分配方式:堆都是动态分配没有静态分配栈有2种分配方式:静态分配和动态分配静态分配是编译器完成比如局部变量分配动态分配由alloca进行分配但是栈动态分配和堆是区别动态分配是由编译器进行释放无需我们手工实现
分配效率:栈是机器系统提供数据结构计算机会在底层对栈提供支持:分配专门寄存器存放栈地址压栈出栈都有专门指令执行这就决定了栈效率比 较高堆则是C/C库提供机制是很复杂例如为了分配块内存会按照算法(具体算法可以参考数据结构/操作系统)在堆 内存中搜索可用足够大小空间如果没有足够大小空间(可能是由于内存碎片太多)就有可能系统功能去增加数据段内存空间这样就有机会分 到足够大小内存然后进行返回显然效率比栈要低得多
从这里我们可以看到堆和栈相比由于大量/delete使用容易造成大量内存碎片;由于没有专门系统支持效率很低;由于可能引发用户态 和核心态切换内存申请代价变得更加昂贵所以栈在中是应用最广泛就算是也利用栈去完成过程中参数返回地址 EBP和局部变量都采用栈方式存放所以我们推荐大家尽量用栈而不是用堆
虽然栈有如此众多好处但是由于和堆相比不是那么灵活有时候分配大量内存空间还是用堆好


无论是堆还是栈都要防止越界现象发生(除非你是故意使其越界)越界结果要么是崩溃要么是摧毁堆、栈结构产生以想不到结果,就 算是在你运行过程中没有发生上面问题你还是要小心说不定什么时候就崩掉那时候debug可是相当困难:)[Page]
对了还有件事如果有人把堆栈合起来说那它意思是栈可不是堆呵呵清楚了?
用来控制变量存储方式和可见性
内部定义变量执行到它定义处时编译器为它在栈上分配空间在栈上分配空间在此执行结束时会释放掉这样就产生了个问题: 如果想将中此变量值保存至下如何实现? 最容易想到思路方法是定义个全局变量但定义为个全局变量有许多缺点最明显缺点是破坏了此变量访问范围(使得在此中定义变量不仅仅受此 控制) 需要个数据对象为整个类而非某个对象服务,同时又力求不破坏类封装性,即要求此成员隐藏在类内部对外不可见

内部机制:
静态数据成员要在开始运行时就必须存在运行中被所以静态数据成员不能在任何内分配空间和
这样空间分配有 3个可能地方是作为类外部接口头文件那里有类声明; 2是类定义内部实现那里有类成员定义; 3是应用()全局数据声明和定义处
静态数据成员要实际地分配空间故不能在类声明中定义(只能声明数据成员)类声明只声明个类“尺寸和规格”并不进行实际内存分配所以在类声 明中写成定义是它也不能在头文件中类声明外部定义那会造成在多个使用该类源文件中对其重复定义
被引入以告知编译器将变量存储在静态存储区而非栈上空间静态
数据成员按定义出现先后顺序依次注意静态成员嵌套时要保证所嵌套成员已经化了消除时顺序是反顺序

优势:
可以节省内存它是所有对象所公有因此对多个对象来说静态数据成员只存储供所有对象共用静态数据成员值对每个对象都是但它 值是可以更新只要对静态数据成员值更新保证所有对象存取更新后相同这样可以提高时间效率

引用静态数据成员时采用如下格式:
<类名>::<静态成员名>
如果静态数据成员访问权限允许话(即public成员)可在按上述格式
来引用静态数据成员

PS:
(1)类静态成员是属于整个类而非类对象所以它没有this指针这就导致
了它仅能访问类静态数据和静态成员
(2)不能将静态成员定义为虚
(3)由于静态成员声明于类中操作于其外所以对其取地址操作就多少有些特殊[Page]
变量地址是指向其数据类型指针 地址类型是个“nonmember指针”

(4)由于静态成员没有this指针所以就差不多等同于nonmember结果就
产生了个意想不到好处:成为个callback使得我们得以将C和C-based X W
indow系统结合同时也成功应用于线程身上
(5)并没有增加时空开销相反她还缩短了子类对父类静态成员访问
时间节省了子类内存空间
(6)静态数据成员在<定义或介绍说明>时前面加关键字
(7)静态数据成员是静态存储所以必须对它进行
(8)静态成员化和般数据成员化区别:
化在类体外进行而前面不加以免和般静态变量或对象相混淆;
化时不加该成员访问权限控制符privatepublic等;
化时使用作用域运算符来标明它所属类;
所以我们得出静态数据成员格式:
<数据类型><类名>::<静态数据成员名>=<值>
(9)为了防止父类影响可以在子类定义个和父类相同静态变量以屏蔽父类影响这里有点需要注意:我们说静态成员为父类和子类共享但我们有 重复定义了静态成员这会不会引起呢?不会我们编译器采用了种绝妙手法:name-mangling 用以生成唯标志

0

相关文章

读者评论

发表评论

  • 昵称:
  • 内容: