C++中系统内存分区:
http://gaofeilonglcu.blog.163.com/blog/static/130864291201082084933665/(貌似是个高手写的)
在C++中,内存可分为系统数据区,自由存储区,文本区,const数据区,全局静态区,堆区和栈区。其中,系统数据区存放的是系统数据,我们是不能自由
访问的,有时候windows系统会突然弹出一个消息框,内容是“内存不能为read”就是错误访问系统数据区的结果;自由存储区用来存放由C延伸而来的
malloc()函数所分配的数据;文本区存放着我们的函数代码,我们调用函数时的底层行为就类似于先去操作一个指针,而这个指针就指向函数指令所在的地
址,也就是在文本区中;const数据区,顾名思义,就是存放不可修改的数据的内存区域,我们定义的const变量都存放在这里。最后,我们来看全局静态
存储区、堆区和栈区。
先来看全局静态存储区,在程序中,由static标号定义的数据都存放在全局静态存储区中,不论是在main()函数之外的定义的全局变量,还是在子函数
中定义的局部变量,只要在定义之前有static标号,定义之后就会始终存在于全局静态存储区中。当然,在main()函数之外定义的全局静态变量在任何
地方都可以访问,而在子函数中定义的局部静态变量只有在定义该变量的模块中可见。但是也存在这样一种现象:如前边所述,即使在子函数中定义的局部静态变
量,其存在形式也是静态的,也就是说,只要在变量定义的语句执行之后,即使在变量不可见的地方,只要对该变量所在的地址取地址解析操作,也是可以获得该变
量的值的。比如我们在函数fun()中定义了一个static
int
a=100;假设该变量的地址是0x0042AD54,我们在main()函数中调用fun()之后,如果对0x0042AD54取地址解析,也是可以得
到100的:int*
p=(int*)0x0042ad54; int
b=*p;这里b被赋值100。由此,我们可以看到,凡是有static定义的变量的生命周期就是整个程序的生命周期,直到程序退出,静态变量所占据的内
存才会被释放。
堆存储区的行为类似于静态存储区,当我们在堆上分配内存之后,如果不进行手动的释放,其内存是不会自动释放掉的。但是在JAVA中,有一种叫做垃圾清理的
机制可以自动清理堆内存,但是在C++中没有这样的机制。也就是说,在C++中,如果我们分配了堆内存,就必须手动释放它。否则如果我们不停的分配堆内
存,但是不对其进行释放,当对内存被耗尽是就会造成程序崩溃。
一般地,用new分配的变量是存放于堆内存中的,但是返回的指针变量是存放在栈中的。当我们在一个子函数中new了一个变量,但是在函数返回时既没有保存
new返回的指针,也没有delete时,就会造成内存泄露。如果我们写的是服务器程序,不断地内存泄露所造成的最终结果就是服务器死机。但是在
windows、linux以及其他一些成熟的系统中,都有类似于内存保护的机制。系统会给用户程序分配一定的运行所需的内存,同是也会给系统自身的运行
保留一部分内存,这部分内存是用户程序所不能访问的。如果我们编写的程序存在内存泄露,当耗尽系统给应用程序分配的内存之后,程序就会停止运行,而不会造
成系统的司机。
至于栈内存,也是我们在写程序中用到的最多的情况。程序中定义的
每一个临时对象,new所返回的指针,以及递归函数中变量都是存放在栈中的。栈内存是可以自动释放的,当我们在某个模块中定义了一个对象,在该模块结束
时,变量所占据的内存就会被系统回收,在定义新的变量时,新的变量就有可能存放在原变量所在的地址上,但是在系统回收栈内存的时候,是不会清空所释放的栈
内存中的数据的,只是将栈顶重新调整,并在新数据的到来时将其分配到栈顶。
在C++中,虽然可以自由操作内存,但这种技术就像是一把双刃剑,用好了锋利无比,用不好反而会造成一些自己都不能理解的莫名其妙的结果。深入理解内存的分配方式,对于实际编程是大有助益的。
程序内存分区:
http://blog.csdn.net/xiuuriel/archive/2006/09/27/1293999.aspx
在C++中,内存分成6个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区,程序代码段。
栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。里面的变量通常是局部变量、函数参数等。
堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。
全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。
常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改,而且方法很多,在《const的思考》一文中,我给出了6种方法)
//main.cpp
int a =
0; 全局初始化区
char *p1;
全局未初始化区
main()
{
int b;
栈
char s[]
= "abc"; 栈
char *p2;
栈
char *p3
= "123456"; 123456在常量区,p3在栈上。
static
int c =0; 全局(静态)初始化区
p1 =
(char *)malloc(10);
p2 =
(char *)malloc(20);
分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456");
123456放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
}
明确区分堆与栈
http://blog.csdn.net/adermxl/archive/2010/10/02/5918685.aspx
什么是堆:堆是大家共有的空间,分全局堆和局部堆。全局堆就是所有没有分配的空间,局部堆就是
用户分配的空间。堆在操作系统对进程 初始化的时候分配,运行过程中也可以向系统要额外的堆,但是
记得用完了要还给操作系统,要不然就是内存泄漏。
什么是栈:栈是线程独有的,保存其运行状态和局部自动变量的。栈在线程开始的时候初始化,每个
线程的栈互相独立。每个函数都有自己的栈,栈被用来在函数之间传递参数。操作系统在切换线程的时候
会自动的切换栈,就是切换SS/ESP寄存器。栈空间不需要在高级语言里面显式的分配和释放。
以上的概念描述是标准的描述,不过有个别语句被我删除,不知道因为这样而变得不标准了^_^.
在bbs上,堆与栈的区分问题,似乎是一个永恒的话题,由此可见,初学者对此往往是混淆不清的,所以我决定拿他第一个开刀。
首先,我们举一个例子:
void
f()
{
int*
p=new
int[5];
}
这条短短的一句话就包含了堆与栈,看到new,我们首先就应该想到,我们分配了一块堆内存,那么指针p呢?他分配的是一块栈内存,所以这句话的意思就是:在栈内存中存放了一个指向一块堆内存的指针p。在程序会先确定在堆中分配内存的大小,然后调用operator
new分配内存,然后返回这块内存的首地址,放入栈中,他在VC6下的汇编代码如下:
00401028
push
14h
0040102A
call
operator
new
(00401060)
0040102F
add
esp,4
00401032
mov
dword
ptr
[ebp-8],eax
00401035
mov
eax,dword
ptr
[ebp-8]
00401038
mov