文章目录
一、C程序中全局/局部变量、堆、栈变量分配
1、存储分配方式
从静态存储区域分配: 内存在程序编译时已经分配好,在程序的整个运行期间都存在。例如全局变量,静态变量。
在栈上创建 : 在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。效率很高,但分配的内存容量有限。
从堆上分配: 动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由程序员决定,使用灵活,但如果在堆上分配了空间,就有责任回收它,否则运行的程序会出现内存泄漏,频繁地分配和释放不同大小的堆空间将会产生堆内碎块。
2、内存分配
C语言程序占用的内存分成了五个部分内容:
栈区:stack, 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等,内存的分配是连续的,即所分配的内存是在一块连续的内存区域内.当我们声明变量时,编译器会自动接着当前栈区的结尾来分配内存。
堆区: 一般由程序员分配释放, 若程序员不释放,程序结束时可能由操作系统回收。类似于链表,在内存中的分布不是连续的,它们是不同区域的内存块通过指针链接起来的。一旦某一节点从链中断开,我们要人为的把所断开的节点从内存中释放。
全局区:static,也称静态区。全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在同一块区域, 未初始化的全局变量和静态变量在相邻的另一块区域。 程序结束后由系统释放
文字常量区:放置常量字符串, 程序结束后由系统释放。
程序代码区:存放函数体的二进制代码。
3、内存属性
静态分配内存:是在程序编译和链接时就确定好的内存。
动态分配内存:是在程序加载、调入、执行的时候分配/回收的内存。
*Text & Data & Bss
-
text: 也称为代码段(Code),用来存放程序执行代码,同时也可能会包含一些常量(如一些字符串常量等)。该段内存为静态分配,只读(某些架构可能允许修改)。
这块内存是共享的,当有多个相同进程(Process)存在时,共用同一个text段。 -
data: 也有的地方叫GVAR(global value),用来存放程序中已经初始化的非零全局变量。静态分配。
-
data又可分为读写(RW)区域和只读(RO)区域。
-> RO段保存常量所以也被称为.constdata
-> RW段则是普通非常全局变量,静态变量就在其中 -
bss: 存放程序中为初始化的和零值全局变量。静态分配,在程序开始时通常会被清零。
text和data段都在可执行文件中,由系统从可执行文件中加载;而bss段不在可执行文件中,由系统初始化。
这三段内存就组成了我们编写的程序的本体,但是一个程序运行起来,还需要更多的数据和数据间的交互,否则这个程序就是死的,无用的。所以我们还需要为更多的数据和数据交互提供一块内存——堆栈。
堆栈(Heap& Stack)
堆和栈都是动态分配内存,两者空间大小都是可变的。
-
Stack: 栈,存放Automatic Variables,按内存地址由高到低方向生长,其最大大小由编译时确定,速度快,但自由性差,最大空间不大。
-
Heap: 堆,自由申请的空间,按内存地址由低到高方向生长,其大小由系统内存/虚拟内存上限决定,速度较慢,但自由性大,可用空间大。
每个线程都会有自己的栈,但是堆空间是共用的。
3、图解
- text、data(gvar)、bss 在内存中地址较低低的位置(low level address),而堆栈则在相对较搞的位置。
- 堆(Heap)往高地址方向生长,栈(Stack)往低地址方向生长。
二、在Ubuntu(x86)系统和STM32(Keil)中分别进行编程、验证
进行验证的程序代码
#include <stdio.h>
#include <stdlib.h>
//定义全局变量
int init_global_a = 5;
int uninit_global_a;
static int inits_global_b = 6;
static int uninits_global_b;
void output(int a)
{
printf("anaconda");
printf("%d",a);
printf("\n");
}
int main( )
{
//定义局部变量
int a=6;
static int inits_local_c=6, uninits_local_c;
int init_local_d = 1;
output(a);
char *p;
char str[10] = "ghz";
//定义常量字符串
char *var1 = "1234567890";
char *var2 = "abcdefghij";
//动态分配
int *p1=malloc(4);
int *p2=malloc(4);
//释放
free(p1);
free(p2);
printf("栈区-变量地址\n"