C语言内存空间管理

一、C语言空间管理

内存

物理内存是最终数据的归属地,编程到最后一定是要操控物理内存的。
裸机编程:直接操作硬件的编程。单片机、MCU编程。这种对硬件编程的可移植性非常差。

带操作系统

操作系统给C语言提供了“假的内存”,即虚拟内存。OS隐藏了不同机器的硬件资源,可以为程序员屏蔽硬件细节。
虚拟内存的大小由操作系统的位数决定。

  • 空间管理:操作系统对相关的 虚拟内存区域的 分段的行为
  • 空间有多大:跟操作系统的寻址能力,即操作系统的位数有关

空间管理的逻辑、分段 segment

分了哪些段
  1. 操作系统内核段:不允许访问,由操作系统保护,一旦访问会被操作系统杀掉程序,OS会提供系统调用来访问这个区域。
  2. 栈段:存放临时变量(局部变量),即函数被调用后,它内部申请的数据。函数一旦返回,那么刚才放到这个区域里面的变量就会被“弹出”。
  3. 堆段:程序提供一个完全由程序员来决定空间生命周期的一个区域。
  4. 数据段:存放全局变量等。生命周期从程序运行开始,程序终止结束。
  5. 代码段:函数里面写的所有的指令,是只读的,一写就出错
4G      -------------
		操作系统内核段     不许访问 操作系统保护   被操作系统杀掉这个程序  OS提供系统调用
3G      -------------
		栈段            存放临时变量 局部变量 函数被调用后,该函数内部申请的数据,函数一旦返回
							刚刚放到这个区域里的变量,就被“弹出”
		堆段             生命周期由程序员来管理 malloc free        
		
		数据段           全局变量    生命周期:程序运行start 程序终止end
			// 下面这些段了解就行
			.data         初始化的全局变量 静态变量 区域
				fun2_data	//假设data是fun2和fun3的静态变量,编译器会帮我们重命名它们
				fun3_data
			.bss          未初始化全局变量 静态变量 区域
			.rodata       只读数据段  "hello world"   一写就出错
		代码段           函数里写的所有的指令      只读  一写就出错
small   ------------- 非常非常小的一块区域
		OS保护区        不许访问 读写都不行 被操作系统杀掉这个程序 
0G      -------------
static关键字

静态区关键字,把这个变量不在存放默认区域里,只存放在数据区,帮你重命名fun3_data

int *fun3() {
	static int data[10];	// 告诉程序,要想通过data访问内存,只能在这个区域里面才能访问
	return data;	// 返回后,可以通过地址访问
}

每个段里存放数据的生命周期(一定要知道)

a.栈
  1. 函数调用后,变量申请在栈上
  2. 函数返回后,变量从栈上“消失”
  3. 栈段有大小限制,如果函数中的局部变量非常多,会导致栈溢出
b.堆
  1. :调用malloc后,操作系统会在堆段中找一个没有被使用的区域,标记出来,返回首地址。
  2. :将堆区的这个首地址交给free的函数后,操作系统就会去堆区里面找它,然后把它标记为“未使用”。如果这个首地址再交给free,此时操作系统会抛出double free的异常(会让程序直接死掉)。
  3. :程序退出。如果堆中只申请,不释放,那么它会导致内存不足。如果再申请,会返回NULL,所以使用malloc时得判断一下是不是为空。
  4. malloc的申请单位是按照字节申请
int *fun1(int n) {
	int *p1 = (int *)malloc(sizeof(int) * n);	// 申请5个int空间,返回这个空间的首地址。由于malloc返回的地址并没有类型,所以前面要加一个(int *)来强转,拿该类型的指针来接收
	struct abc *p2 = (struct abc *)malloc(sizeof(struct abc) * n);
	
	// 一旦执行到return , p1、p2会消失,而它们申请的空间却没有消失
	// 此时,整个系统,都没有人找得到它们申请的空间,所以要在p1、p2消失前,把这个信息通过函数的返回值给上层
    return p1;
}

SUFE大二在读