堆 栈-相关知识【转】

一、预备知识—程序的内存分配

一个由c/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放 
4、文字常量区—常量字符串就是放在这里的。 程序结束后由系统释放
5、程序代码区—存放函数体的二进制代码。

二、例子程序 
这是一个前辈写的,非常详细

//main.cpp
int a = 0; //全局初始化区
char *p1; //全局未初始化区
main()
{
int b; //栈
char s[] = "abc"; //栈
char *p2; //栈
char *p3 = "123456"; //123456\0在常量区,p3在栈上。
static int c =0; //全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
//分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456"); //123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
} 



二、堆和栈的理论知识 

2.1申请方式 

stack: 
由系统自动分配。 例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间 
heap: 
需要程序员自己申请,并指明大小,在c中malloc函数 
  如p1 = (char *)malloc(10); 
在C++中用new运算符 
  如p2 = (char *)malloc(10); 
但是注意p1、p2本身是在栈中的。

2.2 申请后系统的响应 
栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。 
堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时, 
会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。

2.3申请大小的限制 
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。 
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

2.4申请效率的比较: 
栈由系统自动分配,速度较快。但程序员是无法控制的。 
堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便. 
另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活。

2.5堆和栈中的存储内容 
栈: 在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。 
当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。 
堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。

2.6存取效率的比较

char s1[] = "aaaaaaaaaaaaaaa";
char *s2 = "bbbbbbbbbbbbbbbbb";
//aaaaaaaaaaa是在运行时刻赋值的;
//而bbbbbbbbbbb是在编译时就确定的;
//但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。
//比如:
#include
void main()
{
char a = 1;
char c[] = "1234567890";
char *p ="1234567890";
a = c[1];
a = p[1];
return;
} 

对应的汇编代码

10: a = c[1];
00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh]
0040106A 88 4D FC mov byte ptr [ebp-4],cl
11: a = p[1];
0040106D 8B 55 EC mov edx,dword ptr [ebp-14h]
00401070 8A 42 01 mov al,byte ptr [edx+1]
00401073 88 45 FC mov byte ptr [ebp-4],al 

第一种在读取时直接就把字符串中的元素读到寄存器cl中,

第二种则要先把指针值读到edx中,在根据edx读取字符,显然慢了。

2.7小结: 
堆和栈的区别可以用如下的比喻来看出: 
使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。 
使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。

时间: 2024-08-07 21:20:33

堆 栈-相关知识【转】的相关文章

java堆栈相关知识

Java栈与堆 本博客内容由网上搜集而来,作者加以修改整理而成 1. 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方.与C++不同,Java自动管理栈和堆程序员不能直接地设置栈或堆. 2. 栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器.但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性.另外,栈数据可以共 享,详见第3点.堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据.但缺点是,由

面试总结(一)——Java基础相关知识

面试总结(一)--Java基础相关知识 最近在面试,所以总结下面试容易问到的知识点,用来备份查看用. 若需转载,请注明出处. 1.面向对象的特点: 1.将复杂的事情简单化 2.面向对象将以前过程中的执行者,变成了指挥者 3.面向对象思想是符合人们思考习惯的思想 2.面向对象特征: 1.封装:隐藏对象的属性和实现的细节,仅对外提供公共访问方式 好处:将变化隔离,便于使用,提高复用和安全性. 原则:将不需要对外提供的内容隐藏起来,隐藏属性,提供公共方法对其访问. 2.继承:提高代码复用性,继承是多态

深入浅出安卓学习相关知识,如何从零学好移动开发

原文发表自我的个人主页,欢迎大家访问 http://purplesword.info/mobile-develop 由于近几年来互联网的飞速发展,安卓和iOS平台的大量普及推广,移动开发在当前是非常热门的一个方向. 有不少同学问我如何学习安卓,要学些什么,难不难学.之前一直没有想好应该怎么回答这个问题,只是简单的说安卓自身门槛不高,并不难学.因为我觉得准确回答一个类似这样的问题往往需要灵感.现在根据我的学习体验,做个大概的总结. 1.我为什么学安卓 我从刚开始接触安卓开发到现在也有两三年的时间了

程序员面试笔试宝典学习记录(三)(数据库相关知识)

关系数据库系统与文件数据库系统的区别如下: (a)关系数据库系统的主要特征是数据的结构化,而文件数据库系统是数据的非结构化. (b)关系数据库系统中,用户看到的逻辑结构是二维表,而文件数据库系统中,基本元素是文件. (c)文件数据库系统可以实现多媒体文件管理,支持C/S工作模式. acid,指数据库事务正确执行的四个基本要素的缩写.包含:原子性(atomicity),一致性(consistency),隔离性(isolation),持久性(durability). 数据查询:select sele

链表的相关知识整理

链表的相关知识整理 什么是链表 链表是一种物理存储单元上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的.链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成.每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域. 链表与数组的区别 回忆下数组的概念 ,所谓数组,是相同数据类型的元素按一定顺序排列的集合.根据概念我们可以知道数组在内存中连续,链表不连续:由于不同的存储方式导致数组静态分配内存,链表动态分配内存,数组

Java 容器相关知识全面总结

Java实用类库提供了一套相当完整的容器来帮助我们解决很多具体问题.因为我本身是一名Android开发者,包括我在内很多安卓开发,最拿手的就是ListView(RecycleView)+BaseAdapter+ArrayList三剑客, 平时接触使用的容器也只有ArrayList和HashMap.导致对于整个Java容器体系的掌握和使用还停留在很浅的层面.省不足而思改进,那么跟着我来总结一下Java容器的相关知识吧. 结构 java容器类的继承结构 具体介绍 迭代器 Collection Lis

无线性能测试相关知识

几个容易混淆的概念: 备注:灰度测试,小部分的投放市场,大部分用户采用原来的应用,小部分的采用新版本. 性能测试和负载测试等的主要区别是目的不同 负载测试是通过改变系统负载方式.增加负载等来发现系统中所存在的性能问题.负载测试是一种测试方法,可以为性能测试. 压力测试所采用.负载测试的加载方式也有很多种,可以根据测试需要来选择. 性能测试是为获取或验证系统性能指标而进行测试(特定负载).多数情况下,性能测试会在不同负载情况下进行. ·压力测试通常是在高负载情况下来对系统的稳定性进行测试,更有效地

Redis相关知识整理

Redis相关知识整理 1. Redis和MySQL的区别?a).mysql是关系型数据库,而redis是NOSQL,非关系型数据库.mysql将数据持久化到硬盘,读取数据慢,而redis数据先存储在缓存中,读取速度快,但是保存时间有限,最后按需要可以选择持久化到硬盘. b).mysql作为持久化数据库,每次访问都要在硬盘上进行I/O操作.频繁访问数据库会在反复连接数据库上花费大量时间.redis则会在缓存区存储大量频繁访问的数据,当浏览器访问数据的时候,先访问缓存,如果访问不到再进入数据库.

python的list相关知识

关于list的相关知识 list01 = ['alex',12,65,'xiaodong',100,'chen',5] list02 = [67,7,'jinjiao_dawang','relax1949',53] #打印list01.list02 print(list01) print(list02) #列表截取.切片 print(list01[1]) print(list01[-2]) print(list01[1:3]) #列表重复 print(list01 * 3) #列表组合 prin