一、内存分段结构说明
c语言分段管理
1、为什么分段
int a = 10;--操作系统向内存中(哪个区域)申请了一个4B的空间,用a来标记
(哪个区域)--分区域管控(默认行为,自定义行为)
2、分段的对象
裸机开发:没有虚拟地址
C语言--函数语言(函数与函数需要分离)-- 栈 -- PA(指定一个栈区域)
OS开发:VA(虚拟地址)--(MMU)--PA(物理地址)
VA分段:32bit--4G
64bit--256T(使用48bit)
3、如何分段
0x00000000--0xC0000000--提供3G
0xFFFFFFFF
1G————操作系统内核区,不可读不可写--产生段错误
0xC0000000
3G————用户区
动态区:
1、栈的区域--(向下递增的)在这个区域里存放变量的生命周期:函数进入,函数返回
函数里定义的变量,默认就是申请在栈上的(数组、变量)
栈上的生命周期由C语言的编译器来维护(自动在转换为汇编语言时,操作当前CPU体系结构下的栈寄存器SP)
栈是有可能溢出的,栈中不能存放过多的局部变量
每个子函数中栈的区域是有限的
2、堆的区域--(向上递增的)--可以申请比较大的区域, 这个区域是操作系统为程序员提供的一个由程序员自己维护管理的区域
申请:提供了一个malloc函数,向操作系统申请执行申请相应的区域(个数--字节数--内存数)
释放:提供了一个free函数,向操作系统执行释放动作
在这个区域里存放变量的生命周期:malloc申请,free释放--注意内存泄漏和野指针
静态区:编译时已确定
1、数据区(不存在函数局部变量里的数据):全局变量(初始化的data、未初始化的不是bss)、static修饰的变量
在可执行文件中就已经存在
包含了文件中的这块内容,最终加载到内存的哪个位置上
生命周期:程序运行,程序退出
常量区--可读不可写--rodata
常驻内存
2、代码区(存储函数、指令):可执行文件里的主要文件--可读不可写
0x08048000
————保护区,不可读不可写
0x00000000
二、内存堆空间的使用
malloc free :stdlib.h提供
void *malloc( size_t size );
void free( void * );
例:在堆中申请100个int类型的空间
int *p = (int *)malloc( 100*sizeof(int) );--只申请空间而不使用会造成地址泄漏
判断内存是否申请成功(如果申请空间过多,有可能出现内存和硬盘频繁交换数据的情况)
if( p == NULL ){
printf( "malloc failed!" );
return;
}
if( p ){
free( p );//一次性全部释放
p = NULL;
}
常见错误:
1、malloc申请单位是字节,多个元素时,记得写sizeof(元素类型)
2、malloc的返回值要保存给一个指针,并且使用强制类型转换,并判断返回值是否为NULL(内存空间是否申请成功)
3、堆区中,不能double free ,修改方法:free后,将原指针赋值为NULL(空)(相当于对0x00--00地址进行访问)
4、堆区中,free后的空间,继续使用时,编译器是不会报错的,执行也不会被操作系统认为是段错误
而是有可能引起其他代码程序执行的数据异常--注意内存泄漏和野指针
函数返回值是地址:
1、绝对不是局部变量
2、可能是返回堆区空间,说明这个函数是成对出现的
3、如果不是成对出现,指向的空间一定是static修饰的变量
三、内存数据区的使用
数据区(不存在函数局部变量里的数据):全局变量(初始化的data、未初始化的不是bss)、static修饰的变量
在可执行文件中已经存在,包含了文件中这块内容加载到内存的哪个位置
static修饰的变量都放在数据区--全局有效
static 修饰了局部变量,本质上还是放入了数据区,地址在编译时已经确定
全局变量与static区别:
1、生命周期无区别
2、核心目标:软件设计思想
全局变量所有函数都能使用
static修饰过后,其余函数不能通过变量名来访问,可通过地址来访问修改
提供了一种设计模式,在通过变量名访问的方式中,static修饰局部变量,
保证这个变量的访问作用域只在这个函数中,地址可以作为返回值
无论函数调用多少次,只有第一次初始化有效,未初始化时自动赋值为0(编译时已有确定位置,需要有确定的值)
static int a = 100;
每次调用a都重新赋值
static int a ;
a = 100;