C语言内存管理笔记
一、按笔者理解:一个程序所占内存可以分为如下四个区域:
1.代码区: 存放函数(包括主函数、子函数)、代码(语句等,但不包含定义变量int a;类似赋值语句)、 正解:程序被操作系统加载到内存时,所有的可执行代码(程序代码指令、常量字符串等)都加载到代码区。 2.静态区:存放全局变量和静态变量 3.堆区:动态分配内存,解决栈解决不了的内存问题,用malloc函数申请内存,也叫堆扩张,用free函数来释放内存,也叫堆缩减。但因为堆的内存是一段一段不连续的,所以容易造成内存碎片等问题。 4.栈区:存放函数形参、局部变量以及进行任务切换时上下文内容的Reg值。 栈的主要作用是函数调用服务,并承担生命周期短、内存需求小的临时数据或对象的存储。注意:int a;但没有写a = 1;等赋值语句。像这类int a的,是程序编译时确定。
二、管理程序内存的三个原则:
1.如果明确知道数据占用多少内存时,数据量少的用栈,数据量大的用堆。 2.在不知道数据占用多少的内存时,但数据对象可能会占用比较大时,建议用堆。 3.如果要动态建立数组,建议用堆。
三、堆内存用法
内存分配成功才可以使用它,malloc的函数原型为
void *malloc(long NumBytes);
free的函数原型为
void free(void *FirstByte);
申请内存举例:
char *p = (char *)malloc(sizeof(x));
在使用内存之前检查指针是否为NULL,if(p == NULL)等语句来判断。 如果指针p是函数的参数,那么在入口处用assert(p!=NULL)进行检查,断言assert被定义为宏的形式:assert(expression),其作用是判断expression是否成立,如果条件不成立,则程序终止运行。还有断言不是函数,其原型定义在<assert.h>头文件中。 注意:malloc和free函数的使用次数要相同即成对存在,就是说申请一段内存,使用完后就要释放这段内存。并将malloc函数返回的指针指向NULL,如上例中的具体流程应为:
char *p = (char *)malloc(sizeof(x));
free(p);
P = NULL;
p指向NULL是安全起见,避免别的程序利用这个指针对已申请的内存空间进行操作,虽然已该内存空间已经被释放。本人理解:这就好比在酒店开房,退房的时候属于你自己的东西都带走了,门卡没有交还给前台,别人可以通过这张门卡打开房间,从而造成非法使用。
PS:正点原子Linux C应用编程中提到C 语言程序是由以下几部分组成: 正文段。也可称为代码段,这是 CPU 执行的机器语言指令部分,文本段具有只读属性,以防止程 序由于意外而修改其指令;正文段是可以共享的,即使在多个进程间也可同时运行同一段程序。 初始化数据段。通常将此段称为数据段,包含了显式初始化的全局变量和静态变量,当程序加载到 内存中时,从可执行文件中读取这些变量的值。 未初始化数据段。包含了未进行显式初始化的全局变量和静态变量,通常将此段称为 bss 段,这一 名词来源于早期汇编程序中的一个操作符,意思是“由符号开始的块”(block started by symbol), 在程序开始执行之前,系统会将本段内所有内存初始化为 0,可执行文件并没有为 bss 段变量分配 存储空间,在可执行文件中只需记录 bss 段的位置及其所需大小,直到程序运行时,由加载器来分 配这一段内存空间。 栈。函数内的局部变量以及每次函数调用时所需保存的信息都放在此段中,每次调用函数时,函数 传递的实参以及函数返回值等也都存放在栈中。栈是一个动态增长和收缩的段,由栈帧组成,系统 会为每个当前调用的函数分配一个栈帧,栈帧中存储了函数的局部变量(所谓自动变量)、实参和返回值。 堆。可在运行时动态进行内存分配的一块区域,譬如使用 malloc()分配的内存空间,就是从系统堆 内存中申请分配的。
|