最近,在一次面试中偶然被问及内存管理的问题,虽然之前在好多书中有所看到,但真正在经过一番思考和回答时发现还是有些哞乱和模糊,于是,就简单的进行描述;
首先,就操作系统方面来讲,内存管理的功能就是为多道程序的运行提供良好的环境,方便用户使用内存,提高内存的利用率以及能从逻辑上扩充内存;因此,内存管理具有以下功能:内存分配、内存保护、地址映射、内存扩充;
内存分配:采用静态和动态两种分配方式;
静态内存分配中,每个作业的内存空间在装入是就确定,而在程序集作业的运行过程不允许在申请申请新的内存空间;而在动态聂存分配方式中,每个作业所要求的基本内存空间也在装入是确定,但允许在运行过程动态申请附加的内存空间;
内存保护:确保每到程序在自己的额内存空间执行;不允许访问OS的程序和数据;也不允许用户程序转移到非共享的其它程序中执行;通常,有内存保护机制设置两个界限寄存器,分别放在正执行程序的上届和下届,而越界检查有硬件完成;
地址映射:多道程序环境下,运行程序地址空间内的逻辑地址和物理地址不相一致,这就必须借助地址映射机制,将逻辑地址转换为内存空间中与之对应的物理地址;
内存扩充:借助于虚拟存储技术,实现逻辑上的内存扩充,而并非去扩大物理内存容量
那么,在C/C++中的内存管理又是怎样呢:
在C/C++中,内存大体分成5个区,他们分别是栈、堆、全局/静态存储区、常量区、代码区。
栈,在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。 它和由malloc等分配的内存块十分相似,不过malloc是用free来结束自己的生命的。
全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。
常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改。
代码区:存放整个程序的代码,数据和代码是分开存储的;
比如:
void f()
{ int* p=new int[5] ; }
//在栈内存中存放了一个指向一块堆内存的指针p。程序会先确定在堆中分配内存的大小,然后调用operator new分配内存,然后返回这块内存的首地址,放入栈中.
注意:
malloc申请的是连续的一块内存,当返回NULL表示内存申请失败。
if(p == NULL)
{
exit(1); // 终止整个程序; 栈出现内存泄露情况通常是由没有回收垃圾资源,没有进行内存释放引起的
}
free(p);斩断了指针与这块内存的关系,
虽然指针P仍然保存原来的地址,但是已经失去了对那块内存的控制权,同样,对应的那块内存虽然内容存在,不过,已经无法利用其中的数据,成为垃圾文件。对于每次malloc()只能有一次free(),若free()两次会出错,除非原指针指向NULL;
测试程序:
- #include <stdio.h>
- static int x; //全局静态变量
- char ar[2]; //全局普通变量(静态区)
- char *s = "abcdef"; //常量区
-
- void fun(int i)
- {
- int j = i;
- static int a = 100;
- static int b;
- printf("子函数的参数: 0x%p = %d\n", &i, i);
- printf("子函数 栈中数据地址: 0x%p = %d\n", &j, j);
- printf("子函数 静态数据地址(有初值): 0x%p = %d\n", &a, a);
- printf("子函数 静态数据地址(无初值): 0x%p = %d\n", &b, b);
- }
- int main()
- {
- int i = 5;
- static int a = 100;
- static int b;
-
-
printf("全局静态变量地址:0x%p\n", x);
-
printf("全局普通变量地址:0x%p\n",ar[0]);
-
printf("常量地址:0x%p\n",s);
- printf("主函数 栈中数据地址: 0x%p = %d\n", &i, i);
- printf("主函数 静态数据地址(有初值): 0x%p = %d\n", &a, a);
- printf("子函数 静态数据地址(无初值): 0x%p = %d\n", &b, b);
- putchar('\n');
- fun(i);
- return 0;
- }
全局变量和局部变量有什么区别?是怎么实现的?操作系统和编译器是怎么知道的?
生命周期不同:全局变量随主程序创建和创建,随主程序销毁而销毁;局部变量在局部函数内部,甚至局部循环体等内部存在,退出就不存在;内存中分配在全局数据区。
使用方式不同:通过声明后全局变量程序的各个部分都可以用到;局部变量只能在局部使用;分配在栈区。
操作系统和编译器通过内存分配的位置来知道的,
全局变量分配在全局数据段并且在程序开始运行的时候被加载。局部变量则分配在堆栈里面。