代码运行模型
代码段 :是一块内存,只读的,存放编译好的代码指令。
数据段:用来存放全局变量的,但我们第定义一个全局变量数据段就会开出一块内存空间。
堆 :用作动态内存分配。
栈 :用来存放局部变量,和参数。
CPU :核心处理器 用指令寄存器(指令指针)读取一条机器指令到cpu,执行完后在读取下一条指令,cpu会根据每一条指令去操作这些内存。
代码段 :
- 编译器把C语言代码编译成二进制的指令代码(我们编译器编译成的.exe文件);
- 程序运行的时候把二进制代码加载到代码段;
- 代码段只读,不可改写,这样为了安全;
- CPU有一个指令指针,指向当前执行的指令;
- CPU执行完一条指令后,在移动指令指针到下一个位置;
- 指令条件跳转;
- 指令循环跳转;
- 函数调用跳转, 函数返回跳转, 参数传递
数据段
- 每个进程运行程序的时候都会分配一个数据段;
- 数据段存放这个程序中所有的全局变量并为它分配好内存;
- 内存一旦分配好,再也不能增加也不能减少;
堆(动态内存)
- 动态内存:调用操作系统的函数,操作系统会从一个特定的区域里面来分配出一个内存给用户使用,使用完了以后再把这个内存释放;这个特定的区域被称为 堆。
栈
- 操作系统会为每个进程分配一个栈;
- 栈的大小有限,而且大小不大,所以不要在栈上分配大规模的内存块;
- 栈底指针是往下拨动,内存就分配出来,往上拨动,内存回收;
- 局部变量与函数的参数内存都分配在栈上;
int Sum(int a,int b)
{
int c;
c = a + b;
retun c
}
int main(int argc, char** argv)
{
int a = 2; // 定义了一个局部变量a
int b = 3; // 定义了一个局部变量b
int num = 0;
num = Sum(a,b);
system("pause");
return 0;
}
如上代码为例子
但代码一开始执行到
代码指令 —> int a = 2; 的时候会在栈上面分配一个四个字节的空间 a = 3; 并且指针指向该内存上
代码指令 —> int b = 3; 的时候会在栈上面分配一个四个字节的空间 b = 4; 并且指针指向该内存上
代码指令 —> int num = 0; 的时候会在栈上面分配一个四个字节的空间 c = 0; 并且指针指向该内存上
接来来调用 函数 Sum
函数调用过程:
- 分配我们的参数的内存,从参数的右边到左边
- 将参数对应的内存做到数据初始化;
- 将我们的下一条指令的位置,保存在栈里面;
- 保存一下,我们栈顶在调用函数之前的地址;
- 把指令指针拨动到调用函数的地方;
函数返回
- 回收这个函数里面的局部变量,将我们的栈顶拨回到我们没用调用函数前的地方(回收栈内存)
- 将我们的指令指针拨回我们保存的下一条语句要执行的地方;
- 保存我们的返回值到一个地方(EAX寄存器等);
动态内存(堆)
malloc:操作系统的系统调用,从堆上分配指定的内存大小
free 操作系统的系统调用,从堆上释放一块内存
int main(int argc, char** argv)
{
// malloc 是调用操作系统的接口,然后从“堆”上分配出内存空间
// 向这个函数制定要的内存大小
/*
向操作系统 从堆上请求一块存放100 个 int 数据的内存块
malloc返回的是这块内存的起始地址
指针变量是用来存放地址数据的变量
*/
int* p = malloc(100 * sizeof(int));
system("pause");
return 0;
}
执行 int* p = malloc(100 * sizeof(int));
执行 free(p);
如果,没有 free(p) 释放该段内存,就算你不用p这段数据了,计算机还是将这段内存当作是不可用的内存,如果一直申请内存块而没有释放内存的话就会造成内存泄漏,计算机将再也分配不出内存空间, 程序就会挂掉。
个人见解,如有错误欢迎指出