C++程序中不同变量、函数在内存中内存中的分布情况
一、一个C++编译的程序占用的内存分为以下几个部分
1、栈区:由编译器自动分配 存放函数的参数值,局部变量的值等,操作方式类似于数据结构中的栈。
2、堆区:一般由程序员分配释放,若程序员不释放,程序结束时 可能 有系统收回。它与数据结构中的堆是两回事。分配方式类似于链表。
3、全局区(静态区):全局变量和静态变量是存储放在一块的,初始化的全局变量和静态变量在一个区域,未初始化的在相邻的另一个区域。
程序结束后由系统释放。
4、文字常量区:常量字符串就存放在这里。程序结束后有系统自动释放。
5、程序代码区:存放函数体的二进制代码。
二、堆栈的理论知识
1、申请方式
栈:有系统自动分配。例如定义局部变量int i = 0;函数传参时使用值传递。
堆:需要程序员自己申请并指明大小。如用malloc函数和new运算符。
2、申请后的系统响应
栈:只要栈的剩余空间大于所申请的空间,系统将为程序提供内存,负责报告栈溢出异常。
堆:这个设计到系统的内存管理,操作系统有一个记录空闲内存地址的链表,然后根据系统的内存分配策略分配内存。
3、申请大小的限制
栈:在windows下,栈是向低地址扩展的数据结构,是一块连续的内存区域。也就是说栈底和栈顶的地址和最大容量是
系统预先规定好的。在windows下据说是栈大小是2M,如果申请的空间超过栈的剩余空间时将提示溢出。因此栈的
空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区。因为系统用链表来存储空闲内存的地址的,而链表遍历的方向
是从低地址到高地址。堆的大小受限于计算机系统中有效地虚拟内存。获得的空间比较灵活也比较大。
4、效率方面
堆:速度比较慢,容易产生碎片,不过用起来方便。在windows最快的是利用VirtualAlloc分配内存,他不在堆也不在栈中,
而是直接在栈的地址空间中保留一块内存。使用起来速度快,灵活。
栈:速度快,不过由系统自动分配和控制。
5、存放内容方面
堆:一般是在堆的头部用一个字节放堆的大小。堆中具体内容有程序员安排。
栈:在函数调用时第一个进栈的是主函数中下一条指令(函数执行语句的下一条可执行语句)地址,然后是各个函数的参数,
大多数C/C++编译器中,函数参数是从右往左入栈,然后是函数中的局部变量。注意:静态变量不如栈的。本次函数调
用结束后,局部变量先出栈,然后是函数参数,最后栈顶指针指向最开始存的主函数中下一条指令地址,程序由该点继
续运行。
三、实例解说
//全局初始化区
int i1 = 0;
int i2 = 0;
int i3 = 0;
//全局初始化区
static int i4 = 0;
static int i5 = 0;
static int i6 = 0;
//全局未初始化区
int i7;
int i8;
int i9;
void Creat()
{
cout<<"Creat"<<endl;
}
void Add()
{
cout<<"Add"<<endl;
}
void Delete()
{
cout<<"Delete"<<endl;
}
int Max(int a,int b)//在调用此函数时参数从右往左开始压栈
{
return a>b?a:b;
}
int _tmain(int argc, _TCHAR* argv[])
{
cout<<"打印全局初始化区变量i1-i3的地址:"<<endl;
cout<<&i1<<" "<<&i2<<" "<<&i3<<endl;
cout<<"打印全局初始化区静态变量i4-i6的地址:"<<endl;
cout<<&i4<<" "<<&i5<<" "<<&i6<<endl;
cout<<"打印全局未初始化区变量i7-i9的地址:"<<endl;
cout<<&i7<<" "<<&i8<<" "<<&i9<<endl;
cout<<"依次打印上面三个函数Creat、Add、Delete地址:"<<endl;
cout<<&Creat<<endl;
cout<<&Add<<endl;
cout<<&Delete<<endl;
//栈区
int c1 = 'a';
int c2 = 'b';
int c3;
int c4;
cout<<"打印主函数内局部变量c1-c4地址,其中c3,c4未初始化"<<endl;
cout<<&c1<<" "<<&c2<<" "<<&c3<<" "<<&c4<<" "<<endl;
char *pStr1 = "12345";//12345在常量区,pStr在栈上
char *pStr2 = "1122";
void *p = pStr1;
void *q = pStr2;
cout<<"打印常量地址"<<endl;
cout<<p<<endl;
cout<<q<<endl;
static int i10 = 0;//全局(静态)初始化区
cout<<"在局部函数中定义静态变量地址,请于上面答应的其他全局区地址作比较"<<endl;
cout<<&i10<<endl;
int *p1 = new int;//堆区
int *p2 = new int;//堆区
cout<<"打印堆区地址"<<endl;
cout<<p1<<endl;
cout<<p2<<endl;
strcpy(pStr1,"1144");//12345在常量区,编译器可能将pStr1文字常量1144优化成一个地方
getchar();
return 0;
}
输出:
以上结果在VS2008中测试。对上面结果地址观察发现,全局未初始化区的变量是按从高到低地址按申明定义的
顺序压栈,变量i7紧邻全局初始化段的第一个变量i1.而全局初始化段的变量(包括静态,不做区分的)从低地址
到高地址按申明的顺序压栈(不是指上面所指的栈区,请区别开来,这是就地址变化过程而言的,你会看到它与
局部函数变量起始地址完全不同)。函数在程序代码段中地址是按申明顺序递增的。函数局部变量在栈去是按照
申明顺序从高到低的地址进栈的。这里看到我定义的几个int变量地址相差是12个字节还不清楚是不是编译器原因。
常量的开始地址来看跟全局变量应该属于一个区。堆区的地址开头也是另外一个段。
补充一点:数组变量内部元素是按照元素下标从低地址到高地址压栈的。
一般局部变量一般是从高低地址到低地址压栈的。
从上面结果来看全局变量实际可能在堆区。
以上内容主要参考http://blog.csdn.net/benny5609/article/details/2217258原创文章
C++程序中不同变量、函数在内存中内存中的分布情况的更多相关文章
- 如何使用 TP中的公共函数 (定义在common/common.php中的函数)
如何使用 TP中的公共函数 (定义在common/common.php中的函数) (2011-09-30 15:32:09) 转载▼ 标签: 杂谈 1.在common/common.php 中有个 ...
- Linux中环境变量到底写在哪个文件中?解析login shell 和 no-login shell
login shell:取得bash 时需要完整的登入流程,就称为login shell.举例来说,同tty1~tty6登入时, 需要输入用户名和密码,此时取得的bash就称为login shell ...
- 关于全局变量和函数,在其他类中调用问题,extern关键字
1个工程下有几个类文件,和1个全局的文件comm.h, comm.h中存放了这几个类同时需要的变量和同时调用的函数. 当时,我只在comm.h中定义: int commData1: vector&l ...
- 分类器是如何做检测的?——CascadeClassifier中的detectMultiScale函数解读
原地址:http://blog.csdn.net/delltdk/article/details/9186875 在进入detectMultiScal函数之前,首先需要对CascadeClassifi ...
- C++中的友元函数和友元类
C++中的友元函数主要应用于以下场景: 友元函数 第一种场景 代码中有一个全局函数,该函数想要去访问某个类的成员变量(该类的成员变量是private的,且该类并未提供任何获取获取私有成员变量的publ ...
- 面试问题 - SQL 中存储过程与函数的区别
SQL 中的存储过程与函数没有本质上的区别 函数 -> 只能返回一个变量. 函数可以嵌入到sql中使用, 可以在select 中调用, 而存储过程不行. 但函数也有着更多的限制,比如不能使用临 ...
- java中static变量和方法的总结
转自:http://blog.csdn.net/haobo920/article/details/5921621 java中static变量和方法的总结 java中一切皆是对象 一个类中对象的定义一般 ...
- JS:JS中常见的 “函数名 is not a function” 错误
js中常见的错误,例如Uncaught TypeError: x is not a function 其原因除了函数本身有错之外,还有一种很奇怪的情况:函数本身没有错,但是运行时就是不能正常运行.这种 ...
- Entity Framework 6 Recipes 2nd Edition(10-5)译 -> 在存储模型中使用自定义函数
10-5. 在存储模型中使用自定义函数 问题 想在模型中使用自定义函数,而不是存储过程. 解决方案 假设我们数据库里有成员(members)和他们已经发送的信息(messages) 关系数据表,如Fi ...
- 嵌入Python系列 | 调用Python模块中无参数函数
开发环境 Python版本:3.6.4 (32-bit) 编辑器:Visual Studio Code C++环境:Visual Studio 2013 需求说明 在用VS2013编写的Win32程序 ...
随机推荐
- CODEVS 3139 栈练习3
3139 栈练习3 时间限制: 2 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 比起第一题,本题加了另外一个操作,访问栈顶元素(编号3,保 ...
- C#按钮打开浏览器,网址
1.加入 using System.Diagnostics; 2. private void button_main_baidu_Click(object sender, EventArgs e) { ...
- 最常用的CSS技巧收集笔记
1.重置浏览器的字体大小 重置浏览器的默认值 ,然后重设浏览器的字体大小你可以使用雅虎的用户界面重置的CSS方案 ,如果你不想下载9MB的文件,代码如下: body,div,dl,dt,dd,ul, ...
- Ftp不能登陆的解决方法
ftp登陆不了是很经常碰到的事,很多人常常是不加分析就发贴询问.老实说,这样既浪费自己时间,又浪费别人精力,还常常不能得到满意的回答.因此每一位希望从ftp站点发现资源的朋友都有必要学会分析登陆失败的 ...
- 鼠标点击变色 lvha
a标签有四个"状态"的先后过程是:a:link ->a:hover ->a:active ->a:visited.另外,a:active不能设置有无下划线(总是有 ...
- AFNetworking了解
AFNetworking了解 AFNetworking是一个讨人喜欢的网络库,适用于iOS以及Mac OS X. 它构建于在NSURLConnection, NSOperation, 以及其他熟悉 ...
- BZOJ 1977 次小生成树(最近公共祖先)
题意:求一棵树的严格次小生成树,即权值严格大于最小生成树且权值最小的生成树. 先求最小生成树,对于每个不在树中的边,取两点间路径的信息,如果这条边的权值等于路径中的权值最大值,那就删掉路径中的次大值, ...
- XML Schema <第三篇>
验证XML文档是否符合议定的XML结构有两种方法,分别是DTD模式与XML Schema.本文主要介绍XML Schema. 一.XML Schema的优点 XML Schema基于XML,没有专门的 ...
- windows 守护进程
use Win32::Process::Info; while (1==1){ use Sys::Hostname; use HTTP::Date qw(time2iso str2time time2 ...
- shell 中如何判断前一个命令是否执行成功
shell 中如何判断前一个命令是否执行成功 通过判断返回值来解决: if [ $? -eq 0 ];then 命令正确的分支 else 命令失败的分支 fi