计算机中的内存是分区来管理的,程序和程序之间的内存是独立的,不能互相访问,比如QQ和浏览器分别所占的内存区域是不能相互访问的。而每个程序的内存也是分区管理的,一个应用程序所占的内存可以分为很多个区域,我们需要了解的主要有四个区域,通常叫内存四区,如下图:
内存四区域在C语言中,内存的主要分为下列几部分:
内存布局
Text/Code Segment 文本/代码区
Initialized Data Segments 初始化的数据区
Uninitialized Data Segments 未初始化的数据区
Stack Segment 栈区
Heap Segment 堆区
Text/Code Segment 文本/代码区
这个区主要用来保存机器代码,一个可执行对象文件的文本区通常是只读区,可以防止程序被意外修改。文本/代码区可能会被放在堆和栈的下方来防止堆和栈的覆写溢出。
Initialized Data Segments 初始化的数据区
初始化的数据区存储了所有的初始化了的全局的,静态的,常量的,外部的变量。这些变量没有在函数内部定义或者是以静态的方式在函数内部定义了,比如下面两种情况:
int val = 3;
char string[] = "Hello World";
这些变量最初是保存在只读内存中(Text/Code Segment 文本/代码区中),然后被拷贝到了初始化的数据区。
Uninitialized Data Segments 未初始化的数据区
未初始化的数据区,又称作BSS (Block Started by Symbol),这个区一般紧连着初始化的数据区,用来保存所有的初始化为0的全局变量和静态变量,或者没有初始化,比如 static int i;
将会存在BSS中。BSS段属于静态内存分配。
Stack Segment 栈区
栈区是紧连着堆区的,堆和栈的增长方向相反,当堆和栈的指针重合时,此时内存被耗尽。栈区是以后进先出(LIFO)的机制运行的,通常在内存的高地址处。当一个函数被调用时,该函数的返回地址和调用者的环境信息被保存在栈中,新调用的函数再在栈上开辟空间保存自动和临时变量,这就是递归函数的运行机制。当一个递归函数调用它本身时,一个新的栈格被使用,所以这些变量不会跟上次递归的变量相互干扰。栈区主要保存一些局部变量。
每个线程都有自己专属的栈
栈的最大尺寸固定,超出则引起栈溢出
变量离开作用域后栈上的内存会自动释放
Heap Segment 堆区
堆区主要用来动态分配内存。通过malloc, realloc和free来管理。堆区被所有线程,公用库,动态加载模块所共享。
Stack and Heap 堆和栈的区别
在和计算机内存打交道时,我们一定会碰到堆和栈,这两个东西很容易搞混,那么现在就来梳理一下二者的关系。
栈是用来静态分配内存的而堆是动态分配内存的,它们都是存在于计算机内存之中。
栈的分配是在程序编译的时候完成的,直接存储在内存中,接触内存很快。栈是后进先出的顺序,最后被申请的块最先被释放,这样就很容易跟踪到栈,释放栈的过程简单到仅仅是移动下指针就能完成。
堆的分配是在程序运行时完成的,分配速度较为缓慢,但是堆的可用空间非常的大。堆中的元素相互之间没有关联,各自都可以被任何时候随机访问。我们可以任何时候申请和释放一块内存,这样会使得我们很难随时随地追踪到堆中某块位置被分配了还是被释放了。
当你知道在编译前需要分配多少数据时且数据量不是很大时可以使用栈。如果不知道在运行时需要多少数据那么就该使用堆。
在多线程的程序里,每个线程都有其自己独立的栈,它们都共享一个堆。栈是面向线程的而堆是面向进程的。
程序、可执行文件与进程空间映射
... ...
网友评论