C语言的内存管理初探
作为一个本科学的是通信相关不是计算机的研究生对于内存管理一开始根本不懂,由于学通信的关系所以接触到的主要是C语言,
说到C语言没办法不说C语言的精华——指针;说到指针不得不说内存管理的问题
谈到道内存管理就不得不说到你的操作系统是32位还是64位的,虽然内存原理是一样的但是在实践中还是有区别的
1、 对于32位系统内存的寻址范围只有2^32即2^10*2^10*2^10*4=1024*1024*1024*4=1K*1024*1024*4=1M*1024*4=1G*4=4G;
所以32位系统能够识别的内存的最大值只有4个G
最高地址按照16进制的表现为0xf f f f f f f f 8个f 即32位。
2、对于64位操作系统内存的寻址范围有2^64已经达到4G*1024*1024*1024=4EB远远超过的现在程序使用内存的大小
所以现在的64位系统对于大型程序的开发还是有帮助的
3、对于64位操作系统来说,一般实践中用户能够最多用到的内存地址的最大值为0x7fff ffff ffff 即只有48位 比这个地址还要高的地址段为操作系统的内核
对于不同的操作系统中内存地址的分配也是不一样的
由于作者最近一直在使用Linux系统,所以本文中主要采用的是Linux内存管理的形式;
如图这是Linux中内存中的布局
系统内核 |
栈 |
堆 |
数据段 |
代码段 |
下面使用网上最典型的例子来说明内存中栈和堆的区别以及各自的特点
int a = 0; //全局初始化区
char *p1; //全局未初始化区
main()
{
int b; //栈
char s[] = "abc"; //栈
char *p2; //栈
char *p3 = "123456"; //123456\0在常量区,p3在栈上。
static int c =0; //全局(静态)初始化区
p1 = (char *)malloc(10*sizeof(char)); //堆
p2 = (char *)malloc(20*sizeof(char)); //堆
}
一、分配方式
1.栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量等值。其操作方式类似于数据结构中的栈。
2.堆区(heap):一般由程序员分配释放,若程序员不释放,则可能会引起内存泄漏。如果你malloc以及new之后没用free和delete就会出现内存泄露的问题
注堆和数据结构中的堆栈不一样,其类是与链表。
3数据段
4.程序代码区:存放函数体的二进制代码。程序编译之后形成的.o文件存放的位置
由以上几个部分组成:
1>只读数据段:
只读数据段是程序使用的一些不会被更改的数据,使用这些数据的方式类似查表式的操作,由于这些变量不需要更改,因此只需要放置在只读存储器中即可。
一般是const修饰的变量以及程序中使用的文字常量一般会存放在只读数据段中。
2>已初始化的读写数据段:
已初始化数据是在程序中声明,并且具有初值的变量,这些变量需要占用存储器的空间,在程序执行时它们需要位于可读写的内存区域内,并且有初值,
以供程序运行时读写。在程序中一般为已经初始化的全局变量,已经初始化的静态局部变量(static修饰的已经初始化的变量)
3>未初始化段(BSS):
未初始化数据是在程序中声明,但是没有初始化的变量,这些变量在程序运行之前不需要占用存储器的空间。与读写数据段类似,它也属于静态数据区。
但是该段中数据没有经过初始化。未初始化数据段只有在运行的初始化阶段才会产生,因此它的大小不会影响目标文件的大小。在程序中一般是没有初始化的全局变量和没有初始化的静态局部变量。注:声明与定义是不同的,定义就直接会开辟内存空间二声明则不会。
二、使用的方式
栈: 在函数调用时,第一个进栈的是主函数中函数调用后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。
当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。
堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。
注意*p3 与*p1和*p2之间的区别
在64为操作系统中gcc默认一个指针的大小是8个byte,8*8=64bit,刚刚好足够寻址
三、系统性能:
栈: 在函数调用时,第一个进栈的是主函数中函数调用后的下一条指令(函数调用语句的下一条可执行语句)的地址,
然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。
当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。
堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。