***************************************************
更多精彩,欢迎进入:http://shop115376623.taobao.com
***************************************************
http://blog.youkuaiyun.com/yitian20000/article/details/6358837
虽然这些博客写的东西都是天下一把抄的,但是对于我们来说,只是来潜心学习就好。
一、预备知识—程序的内存分配
在函数体中定义的变量通常是在栈上,
用malloc, calloc, realloc等分配内存的函数分配得到的就是在堆上。
在所有函数体外定义的是全局量,加了static修饰符后不管在哪里都存放在全局区(静态区),
在所有函数体外定义的static变量表示在该文件中有效,不能extern到别的文件用,
在函数体内定义的static表示只在该函数体内有效。另外,函 数中的 "adgfdf "这样的字符串存放在常量区。
还有就是函数调用时会 在栈上有一系列的保留现场及传递参数的操作。栈的空间大小有限定,vc的缺省是2M。栈不够用的情况一般是程序中分配了大量数组和递归函数层次太深。有一 点必须知道,当一个函数调用完返回后它会释放该函数中所有的栈空间。栈是由编译器自动管理的,不用你操心。堆是动态分配内存的,并且你可以分配使用很大的 内存。但是用不好会产生内存泄漏。并且频繁地malloc和free会产生内存碎片(有点类似磁盘碎片),因为c分配动态内存时是寻找匹配的内存的。而用 栈则不会产生碎片。在栈上存取数据比通过指针在堆上存取数据快些
堆(heap) 和栈(stack)是C/C++编程不可避免会碰到的两个基本概念。首先,这两个概念都可以在讲数据结构的书中找到,他们都是基本的数据结构,虽然栈更为 简单一些。在具体的C/C++编程框架中,这两个概念并不是并行的。对底层机器代码的研究可以揭示,栈是机器系统提供的数据结构,而堆则是C/C++函数 库提供的。具体地说,现代计算机(串行执行机制),都直接在代码底层支持栈的数据结构。这体现在,有专门的寄存器指向栈所在的地址,有专门的机器指令完成 数据入栈出栈的操作。这种机制的特点是效率高,支持的数据有限,一般是整数,指针,浮点数等系统直接支持的数据类型,并不直接支持其他的数据结构。
因为栈 的这种特点,对栈的使用在程序中是非常频繁的。对子程序的调用就是直接利用栈完成的。机器的call指令里隐含了把返回地址推入栈,然后跳转至子程序地址 的操作,而子程序中的ret指令则隐含从堆栈中弹出返回地址并跳转之的操作。C/C++中的自动变量是直接利用栈的例子,这也就是为什么当函数返回时,该 函数的自动变量自动失效的原因。
和栈不同,堆的数据结构并不是由系统(无论是机器系统还是操作系统)支持的,而是由函数库提供的。基本的 malloc/realloc/free函数维护了一套内部的堆数据结构。当程序使用这些函数去获得新的内存空间时,这套函数首先试图从内部堆中寻找可用
的内存空间,如果没有可以使用的内存空间,则试图利用系统调用来动态增加程序数据段的内存大小,新分配得到的空间首先被组织进内部堆中去,然后再以适当的 形式返回给调用者。当程序释放分配的内存空间时,这片内存空间被返回内部堆结构中,可能会被适当的处理(比如和其他空闲空间合并成更大的空闲空间),以更 适合下一次内存分配申请。这套复杂的分配机制实际上相当于一个内存分配的缓冲池(Cache),使用这套机制有如下若干原因:
1. 系统调用可能不支持任意大小的内存分配。有些系统的系统调用只支持固定大小及其倍数的内存请求(按页分配);这样的话对于大量的小内存分类来说会造成浪费。
2. 系统调用申请内存可能是代价昂贵的。系统调用可能涉及用户态和核心态的转换。
3. 没有管理的内存分配在大量复杂内存的分配释放操作下很容易造成内存碎片。
从以 上知识可知,栈是系统提供的功能,特点是快速高效,缺点是有限制,数据不灵活;而栈是函数库提供的功能,特点是灵活方便,数据适应面广泛,但是效率有一定 降低。栈是系统数据结构,对于进程/线程是唯一的;堆是函数库内部数据结构,不一定唯一。不同堆分的内存无法互相操作。栈空间分静态分配和动态分配两种。 静态分配是编译器完成的,比如自动变量(auto)的分配。动态分配由alloca函数完成。栈的动态分配无需释放(是自动),也就没有释放函数。为可移
植的程序起见,栈的动态分配操作是不被鼓励的!堆空间的分配总是动态的,虽然程序结束时所有的数据空间都会被释放回系统,但是精确的申请内存/释放内存匹 配是良好程序的基本要素。
堆和栈的生长方向恰好相反,
|--------------| 低地址
| 堆 |
|--------------|
| | |
| I |
| |
| ^ |
| 栈 | 高地址
-----------------
所以计算机中的堆和栈经常时放一块讲的
一般不是必要就不要动态创建,最讨厌把new出来的东西当局部变量用,用万了马上delete 的做法.
理由
1.栈分配比堆快,只需要一条指令就呢给配所有的局部变量
2.栈不会出现内存碎片
3.栈对象好管理
当然,某些情况下也要那么写,比如
1.对象很大
2.对象需要在某个特定的时刻构造或析够
3.类只允许对象动态创建,比如VCL的大多数类
当然,必须用堆对象时也不能躲避
堆内存和栈内存各有什么作用?堆:顺序随意
----------------------------------------------------------------------------------------
为什么说在堆上分配
堆空间的管理
堆空间的释放需要系统管理,栈上的释放可以直接丢弃。堆空间需要通过栈上的指针
记 得在apue2上面看到关于线程中有这样一段话,大致意思是,一个 线程有自己的堆栈,可以在堆栈上分配
比如,在栈上分一个int,只要esp-4就可以了,
在堆上系统要记录被分配
----------------------------------
内存
----------------------------------------
一般所说的堆栈(stack)往往是指栈,先进后出,
=========================================================
以下为自己再此测验过程:
liuguanwen@liuguanwen-OptiPlex-990:~/lgw$vi hellopioneer.c
#include
int def;
char ch0;
static double efg;
float flo;
char ch1;
char ch2;
double bac = 0;
double gfe = 0;
static int hoo;
char ch3;
char ch4='0';
int ghk;
int main (int argc, char *argv[])
{
}
:q
liuguanwen@liuguanwen-OptiPlex-990:~/lgw$ gcc hellopioneer.c
liuguanwen@liuguanwen-OptiPlex-990:~/lgw$ l
a.out*
Book/
CCALIB
liuguanwen@liuguanwen-OptiPlex-990:~/lgw$ ./a.out
abc:0xbfe47a9c
argc:0xbfe47ab0
argv:0xbfe47ab4
def:0x804a04c
ch0:0x804a049
efg:0x804a030
flo:0x804a044
ch1:0x804a048
ch2:0x804a03c
bac:0x804a020
gfe:0x804a028
hoo:0x804a038
ch3:0x804a04a
ch4:0x804a014
ghk:0x804a040
st0:0xbfe47a98
st1:0x80486d0
st2:0x80486d0
st3:0x80486d0
hello:0x804a03c
tni:0xbfe47a94
liuguanwen@liuguanwen-OptiPlex-990:~/lgw$
以上是以gcc来编译运行后的结果,从中也可以推断出些结果。当然一开始是用Qt来研究(Qt编译实质也就是gcc),之后gcc只是拿来验证const类型的变量是放在哪个内存区。Qt中代码如下:
#include
#include
int def;
char ch0;
static double efg;
float flo;
char ch1;
char ch2;
double bac = 0;
double gfe = 0;
static int hoo;
char ch3;
char ch4='0';
int ghk;
int main(int argc, char *argv[])
{
}
输出结果:
abc:0xbfe0e89c
argc:0xbfe0e8c0
argv:0xbfe0e8c4
def:0x804a038
ch0:0x804a03c
efg:0x804a060
flo:0x804a040
ch1:0x804a044
ch2:0x804a045
bac:0x804a048
gfe:0x804a050
hoo:0x804a068
ch3:0x804a058
ch4:0x804a028
ghk:0x804a05c
st0:0xbfe0e898
st1:0x8048ae0
st2:0x8048ae0
st3:0x8048ae0
hello:0x804a06c
tni:0xbfe0e894
早先晓得C在变量内存分配中,分四片区(代码区/常量区/栈区/堆区)Code/Const/Stack/Heap
代码区从名字中,就可已晓得,是存放代码的;
常量区也可以从文字中看出,存的是常量,哪些是属于常量,那就得细分下了,比如说char * abc = "hello world!",这个常量串串"hello world!"是存在常量区的(不可改变),而指针变量abc是存在栈区的(当然这个不是malloc/new出来的一部分);
栈区,是大伙儿经常用到的,我int i;这个局部变量啊就是的;
堆区嘛,刚才也说咧,new/malloc出来的东西都存放在这儿,变量及对象都是;
全局区(静态区)经过以上的验证,全局变量及静态变量分在内存的一个区间,只不过在分配时有先后顺序而已,全局变量在先,静态变量在后分配而已。
在这里需要注意一点:属于类的变量(static的),及属于对象的变量,那是存在不同的内存区的,这点C与C++在内存分配上可以说是一样的。
“这点”指的是内存分配上(这点C与C++在内存分配上可以说是一样的) 表达上有点混淆哈,木看懂的还望指出及还望指点指点。