C语言内存管理

不同层次下的内存开辟与释放

  STL  ==> 内存都是自动分配和释放的

     |

   C++ ==> new/delete 会调用malloc/free,并调用构造/析构函数

     |

   C      ==> malloc/free

     |

  UNIX规范(POSIX)  ==> sbrk/brk

     |

  Linux系统  ==>mmap

     |

  ----------------------

  系统调用(内核) ==>  kmalloc/vmalloc

     |

  get_free_page() 获取空闲的内存页面

内存管理

首先简单介绍一下概念:

   程序:在磁盘保存的可以运行的文件

   进程:正在运行的程序,存在于内存中

一个进程空间被划分为以下部分:

操作系统给每个进程拥有独立的4G空间,操作系统会把进程使用到的逻辑地址,映射到物理地址。

0~3G属于用户空间

3~4G属于内核空间

1)代码区:要执行的程序被放入此区,只读区域(08048000开始的一定是代码区,代码区4K)

2)全局区:保存全局变量,mian函数执行前分配

3)BSS段:保存未初始化的全局变量,BSS段在mian函数执行前会被清0(这就是为什么static变量未初始化默认为0)

4)堆区:也叫自由区,保存new,malloc...出来的变量(堆区可能没有,可能有多个,如果没有malloc,就可能没有堆区)

5)栈区:保存局部变量(包括函数参数),内存分配释放都是自动进行的

栈底的地址是用户可访问的最高地址区域,每次在栈内开辟空间,栈顶指针会变小(即地址变小)

堆开始分配的地址比较低,与全局区相邻,每次在堆内开辟空间,开辟的地址比上一次开辟的地址大。

1.段错误

  1.1 对内在空间的操作超出权限的限制,会导致段错误,比如写只读空间

  1.2 访问没有对应物理空间的虚拟地址,会导致段错误

2.对空间的分配

  malloc会在后台维护一个双向链表的数据结构,并且每次malloc会在结束位置有标记(12字节,存有链表信息)

越界访问修改会破坏标记,从而导致内存释放出现问题,总而言之,使用malloc时不要越界访问。

3.内存页面管理(详细查看内存的段页式管理方式)

  操作系统分配物理内存空间时,会按页为单位进行分配。一般系统一页为4096Bytes.操作系统分配好物理空间之后,会给进程

分配虚拟内存与物理空间一一对应起来,进行内存映射。

  对于malloc来说,操作系统第一次会直接分配33个页面的物理空间,并做内存映射,在以后的malloc操作,如果需要的内存没有

超过之前分配的33个页面,操作系统不会再次分配新的空间给进程,只有下次malloc时,上次的页面都用完了,系统会一个一个的

分配页面。

测试代码

#include <stdio.h>
#include <stdlib.h>

int i1 = 10;	//全局
int i2 = 20;	//全局
int i3;			//BSS段
static int i4 = 40;	//全局
const int i5 = 50;	//代码区
void fa(int i6)		//栈区
{
	int i7 = 70;			//栈区
	static int i8 = 80;		//全局区
	const int i9 = 90;		//栈区
	int *pi = malloc(sizeof(int));	//堆区
	char *str = "abcde";		//代码区
	char str2[] = "abcde";		//栈区
	printf("&i6=%p\n", &i6);
	printf("&i7=%p\n", &i7);
	printf("&i8=%p\n", &i8);
	printf("&i9=%p\n", &i9);
	printf("pi=%p\n", pi);
	printf("str=%p\n", str);
	printf("str2=%p\n", str2);
}

int main(int argc, const char *argv[])
{
	printf("&i1=%p\n", &i1);
	printf("&i2=%p\n", &i2);
	printf("&i3=%p\n", &i3);
	printf("&i4=%p\n", &i4);
	printf("&i5=%p\n", &i5);
	fa(6);
	while(1);
	return 0;
}

C语言内存管理_第1张图片C语言内存管理_第2张图片C语言内存管理_第3张图片



你可能感兴趣的:(C语言,内存管理,maps,BSS段)