# 内存管理

简述:

  • :存放程序的 局部变量和函数调用的参数返回地址 。栈是一个 向下增长 的数据类型,具有 后进先出(LIFO) 的特性。栈上的内存由 编译器自动分配和释放 需要 程序员干预栈上内存空间 通常有限,因此不适合存放大量或复制的数据。
  • :存放程序 动态分配 的内存,由程序员 控制其生命周期 。堆是一个 向上增长 的数据结构,可以 根据需要 扩展或收缩。使用 newdelete 操作符分配和释放堆上的内存时,需要注意 内存泄漏野指针 等问题。 delete之后 要将地址设置 为nullptr
  • 数据区 :存放程序的 全局变量和静态变量 ,分为初始化和未初始化两部分。初始化部分包含了程序赋予初始化的变量,未初始化部分包含了程序没有赋予初始化的变量。
  • 代码区 :存放程序的 可执行指令 ,通常是 只读的 ,可以被 多个进程共享

堆空间 大小可以 扩展或收缩 空间大小 有限

堆空间 的访问速度比 空间 堆空间 也容易产生 内存碎片和内存泄漏

堆空间 的地址增长是 向上 的,沿着 内存地址增加 的方向,而 栈空间向下的 ,也就是沿着 内存地址减小 的方向 增长

C语言内存管理

# 代码区

存放程序编译后的 可执行二进制代码CPU 执行的 机器指令 ,并且是 只读的

只读

共享每次打开 exe文件 ,都会指向一个 内存空间

# 全局 / 静态区

全局变量和静态变量的存储是放在一起的,初始化的全局变量和静态变量在 一块区域 ,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域,程序结束后 由系统释放

  • 全局/静态 区存储 全局变量,静态变量,常量,该区变量 在程序运行期间一直存在
  • 程序结束由 系统回收
  • 已初始化的数据放在 data段 ,未初始化的数据放到 bss段
  • 该去变量当未初始化时,会有 默认值初始化

# 堆区

开发者 手动申请,手动释放,若不手动释放,程序结束后由 系统回收 ,声明周期是 整个程序运行期间 ,使用 malloc 进行堆内存申请, 堆的总大小机器的虚拟内存 的大小

  • 堆区由开发人员手动申请与释放,在释放之前,该块 堆空间 可一直使用
  • 由程序员分配和释放,若程序员不释放,程序结束时由 系统回收内存
  • 堆空间 一般没有 软限制 ,只受 限于硬件 ,会比 栈空间更大 ,适宜存放 较大数据

# 被调函数分配内存

void allocateSpace(char * pp)
{ 
	char * temp = malloc(100);  //temp 为局部变量
	memset(temp, 0, 100);
	strcpy(temp, "hello world"); //helloworld 对方到堆区
	pp = temp;  // 传入的参数和 pp 的地址并不相同,pp 作为参数存放在栈中,函数结束释放内存
}
//1. 利用高级指针
void allocateSpac2(char ** pp) //// 使用二级指针,此时 pp 的地址与传入参数地址相同
{
	char * temp = malloc(100);
	memset(temp, 0, 100);
	strcpy(temp, "hello world");
	*pp = temp; // 使用调用的指针来
	printf("aaa%s\n", *pp);
}

# 栈区

编译器 自动分配释放,存放函数的参数值,局部变量的值

  • 栈是一种 先进后出 的内存结构,由编译器自动分配释放数据
  • 主要存放函数的 形式参数值局部变量
  • 函数 运行结束 ,相应 栈变量 会被 自动释放
  • 空间 较小不适合 大量数据存 放在栈中

注意: 不要 返回 局部变量的地址 ,在调用函数之后,局部变量就 已经被释放 ,a 的地址被销毁,在对指针 p 进行访问,就属于 非法访问内存

# 程序指令和程序数据分开原因

  • 程序被加载到内存中之后,可以将 数据和代 码分别 映射 到两个 内存区域 。由于数据区域对进程来说是可读可写的,而 指令区域 对程序来讲是 只读 的,所以分区之后,可以将程序指令区域和数据区域分别设置成只读,这样就可以 防止程序有意或无意被修改
  • 当系统中运行着多个同样的程序时,这些 程序指令 都是 一样 的,所以只需要在内存中保存 一份程序指令 即可,只是每一个程序运行中 数据不一样 而已,这样可以 节省大量的内存

内存分配

# 宏定义

  • 宏定义和宏常量都是利用 #define 定义出来的内容
  • 在项目中,经常把一些 短小而又频繁使用 的函数写成 宏函数
  • 宏函数 没有 普通函数参数 压栈跳转返回 等时间上的 开销

注意:宏函数要 加括号 ,保证运算的完整,宏定义仅负责替换,不复制运行等相关操作。

可以把频繁使用并且短小的函数,写成宏函数,宏函数在编译阶段就替换源码,没有普通函数入栈出栈的开销,以空间换时间

# 参考资料

  • c 内存管理