c/c++内存笔记

C/C++内存笔记

内存占用

  1. 栈区(stack):普通局部变量,由编译器自动分配和释放,存放为运行时函数分配的局部变量、函数参数、返回数据、返回地址等,其操作类似于数据结构中的栈。
  2. 堆区(heap):一般由程序员自动分配,如果程序员没有释放,程序正在运行时不会被自动释放,程序结束时由操作系统回收,其分配类似于链表。
  3. 全局区(静态static):存放全局变量,静态数据,常量,程序结束后系统释放;全局区分配已初始化的全局区(data)和未初始化的全局区(bss)。常量区存放常量支付串,程序结束后由系统释放。
  4. 代码区:存放函数体(类成员函数和全局区)的二进制代码。

内存分配方式

  1. 从静态存储区分配
    内存在程序编译的时候已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。
  2. 在栈上创建
    在执行函数时,函数内局部变量的存储单元可以在栈上创建,函数执行结束时,这些内存单元会自动被释放。
    栈内存分配运算内置于处理器的指令集,效率高,但是分配的内存容量有限。
  3. 从堆上分配
    亦称为动态内存分配。
    程序在运行的时候使用malloc或者new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生命周期有程序员决定,使用非常灵活,但如果在堆上分配了空间,既有责任回收它,否则运行的程序会出现内存泄漏,频繁的分配和释放不同大小的堆空间将会产生内存碎片。

操作系统内存管理

内存一直是计算机系统中最宝贵而又最紧俏的资源,内存能否被有效、合理的使用,将直接影响到操作系统的性能。

管理内存的目的:

一是方便用户使用;
二是提高存储器的利用率。

内存管理能力:

  1. 内存空间的分配与回收
  2. 地址转换,将逻辑地址转换为物理地址
  3. 存储保护和存储共享
  4. 内存空间的扩充

存放区域示例:

#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陷阱与缺陷

posted @ 2020-05-05 20:51  懒人状元  阅读(168)  评论(0编辑  收藏  举报