c/c++内存笔记
C/C++内存笔记
内存占用
- 栈区(stack):普通局部变量,由编译器自动分配和释放,存放为运行时函数分配的局部变量、函数参数、返回数据、返回地址等,其操作类似于数据结构中的栈。
- 堆区(heap):一般由程序员自动分配,如果程序员没有释放,程序正在运行时不会被自动释放,程序结束时由操作系统回收,其分配类似于链表。
- 全局区(静态static):存放全局变量,静态数据,常量,程序结束后系统释放;全局区分配已初始化的全局区(data)和未初始化的全局区(bss)。常量区存放常量支付串,程序结束后由系统释放。
- 代码区:存放函数体(类成员函数和全局区)的二进制代码。
内存分配方式
- 从静态存储区分配
内存在程序编译的时候已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。 - 在栈上创建
在执行函数时,函数内局部变量的存储单元可以在栈上创建,函数执行结束时,这些内存单元会自动被释放。
栈内存分配运算内置于处理器的指令集,效率高,但是分配的内存容量有限。 - 从堆上分配
亦称为动态内存分配。
程序在运行的时候使用malloc或者new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生命周期有程序员决定,使用非常灵活,但如果在堆上分配了空间,既有责任回收它,否则运行的程序会出现内存泄漏,频繁的分配和释放不同大小的堆空间将会产生内存碎片。
操作系统内存管理
内存一直是计算机系统中最宝贵而又最紧俏的资源,内存能否被有效、合理的使用,将直接影响到操作系统的性能。
管理内存的目的:
一是方便用户使用;
二是提高存储器的利用率。
内存管理能力:
- 内存空间的分配与回收
- 地址转换,将逻辑地址转换为物理地址
- 存储保护和存储共享
- 内存空间的扩充
存放区域示例:
#include <stdio.h>
#include <stdlib.h>
int iNUM = 250; //全局区(静态区,已初始化)
int main(int argc, char** argv) {
int iNUM1 ; //栈区
char cNUM3[] = "ABC" ; //栈区
char *cP ; //栈区
char *cP1 = "888888" ; //cP1在栈区,888888在常量区
cP = (char*)malloc(20) ;//堆区
static int iNUM2 = 100 ;//全局区(静态区,已初始化)
return 0;
}
一个程序的内存分区
在程序没有执行前,有几个内存分区已经确定,注意:分区确定但没有加载到内存,程序只有在运行时候才加载到内存:
text(代码区):通常只读;存放函数
data:已经初始化的数据,全局变量,static变量,文字常量区(只读)
bss:没有初始化的数据,全局变量,static变量
当运行程序时,加载内存,首先根据上面确定的3个分区(text,data,bss)先加载,然后额外加载stack(栈区),heap(堆区)
栈越界
即栈区空间使用完,超出栈的使用返回,导致段错误,学习时一般程序不会出现栈越界,一般是在使用函数递归的时候可能会出现栈越界。
堆越界一种情况(内存污染)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char** argv) {
char *p = NULL ;
p = (char*)malloc(0) ;
if(p == NULL){
printf("分配错误\n") ;
}
strcpy(p,"nihao") ;
printf("%s \n",p) ;
return 0;
}
这个程序能够运行出来,但我们能够明显知道代码是错的,但是它能够运行,造成了内存的污染。但是如果我们在return前面free(p)的话就会程序崩溃但他不是free错误,只是你之前没有malloc正确而已。
指针指向栈区空间
int main(){
int *p ;
*P = 10 ;
printf("*p = %d \n",*p) ;
return 0 ;
}
对于这个段函数来说,会出现段错误。因为p指针没有指向,p指针是一个野指针。
解决方式:
//在第二行后面添加
int a ; //定义一个栈区的变量
p = &a ; //指针指向栈区空间
指针指向堆区空间
int main(){
int *p ;
*P = 10 ;
printf("*P = %d \n",*P) ;
return 0;
}
同样的是这段错误的代码,我们使用另一种方式修改它。
//还是在第二行后面添加
//使用malloc函数在堆区申请一段内存
p = malloc(sizeof(int)) ;
//在c++里面需要对malloc申请的内存强转
//p = (int *)malloc(sizeof(int)) ;
if(p == NULL){
printf("内存空间分配失败") ;
return -1 ;
}
//然后在return 0 之前添加释放函数
free(p) ;
提示:malloc动态申请的堆区内存空间不会自动释放,使用完后需要free释放。同一块内存空间只能释放一次。
更多内容等待添加...
参考书籍推荐:
1、C和指针
2、C专家编程
3、C陷阱与缺陷