【PL理论】(26) 内存管理:C语言实现内存管理的方式 | 栈帧的分配和释放 | C/C++ 手动内存管理

本文主要是介绍【PL理论】(26) 内存管理:C语言实现内存管理的方式 | 栈帧的分配和释放 | C/C++ 手动内存管理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  • 💭 写在前面:在前面的章节中,语言的语义只分配了新的内存位置,我们没有讨论内存位置的释放。在实际的语言中,内存位置在执行过程中会被不断地分配和释放。下面的章节,我们将讨论编程语言的这种内存管理,并且我们将重点介绍垃圾回收机制 (一种自动管理动态分配内存的机制) 。在接下来的讲解中,我们不会像之前那样使用编程语言的正式语义定义了。例如,尽管可以形式化地表示简单的垃圾回收方法,但这样会使内容变得过于复杂。取而代之地,我将依赖示例代码和图表来进行高层次的解释。

目录

0x00 案例研究:C语言

0x01 C语言的实现方式

0x02 回顾:栈帧的分配与释放

0x02 C/C++ 手动内存管理


0x00 案例研究:C语言

众所周知,C语言中不同种类的变量具有不同的生命周期 (存储持续时间) :

  • 全局变量在整个程序执行过程中都是存活的
  • 而函数的局部变量仅在该函数执行期间存活
  • 动态内存分配的对象 (malloc, realloc...) 在被 free 释放之前一直存活

作用域和生命周期相关但有微妙的区别 :

  • 作用域是关于名称(标识符)及其解析 
  • 生命周期是关于内存中的存在持续时间

当 f() 返回时,int i 不再存在,而 p 指向的内存在返回后仍然存在。

int n = 10;     // 随时可以访问
int* f(void) {int i;int *p;p = malloc(4);if (...) {return &i;   // 这完全不合理} else {return p;    // 这个有可能}
}

0x01 C语言的实现方式

通常,C 编译器按如下方式实现这个设计:

  • 全局变量 (GV) 放在 数据区 (data section):分配固定地址
  • 局部变量 (LV) 放在栈中:每个函数在入口时分配 栈帧 (stack frame),并在返回前释放它。
  • 将动态分配的对象放在 (Heap) 内存中
  • 这是现存标准 (没官宣),所以你可以将堆视为等同于用于动态分配的内存空间。

0x02 回顾:栈帧的分配与释放

堆帧的分配和释放,可以被视为对局部变量内存的自动管理。

0x02 C/C++ 手动内存管理

在 C/C++ 中,使用 malloc / new 动态分配的内存必须手动释放 (free / delete) 。

这种手动内存管理使得内存空间的使用更加高效,程序员可以精确控制内存的生命周期。

然而,在这个过程中程序员可能会犯下大错!触犯天条!导致项目经理大怒:

  • 内存泄漏:因为程序员忘记释放了
  • 悬空指针:忘了内存已经释放了,释放内存后,又访问了该内存


📌 [ 笔者 ]   王亦优
📃 [ 更新 ]   2024.6.10
❌ [ 勘误 ]   /* 暂无 */
📜 [ 声明 ]   由于作者水平有限,本文有错误和不准确之处在所难免,本人也很想知道这些错误,恳望读者批评指正!

📜 参考资料 

Microsoft. MSDN(Microsoft Developer Network)[EB/OL]. []. .

这篇关于【PL理论】(26) 内存管理:C语言实现内存管理的方式 | 栈帧的分配和释放 | C/C++ 手动内存管理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1066132

相关文章

Django中的函数视图和类视图以及路由的定义方式

《Django中的函数视图和类视图以及路由的定义方式》Django视图分函数视图和类视图,前者用函数处理请求,后者继承View类定义方法,路由使用path()、re_path()或url(),通过in... 目录函数视图类视图路由总路由函数视图的路由类视图定义路由总结Django允许接收的请求方法http

Python yield与yield from的简单使用方式

《Pythonyield与yieldfrom的简单使用方式》生成器通过yield定义,可在处理I/O时暂停执行并返回部分结果,待其他任务完成后继续,yieldfrom用于将一个生成器的值传递给另一... 目录python yield与yield from的使用代码结构总结Python yield与yield

Go语言使用select监听多个channel的示例详解

《Go语言使用select监听多个channel的示例详解》本文将聚焦Go并发中的一个强力工具,select,这篇文章将通过实际案例学习如何优雅地监听多个Channel,实现多任务处理、超时控制和非阻... 目录一、前言:为什么要使用select二、实战目标三、案例代码:监听两个任务结果和超时四、运行示例五

python使用Akshare与Streamlit实现股票估值分析教程(图文代码)

《python使用Akshare与Streamlit实现股票估值分析教程(图文代码)》入职测试中的一道题,要求:从Akshare下载某一个股票近十年的财务报表包括,资产负债表,利润表,现金流量表,保存... 目录一、前言二、核心知识点梳理1、Akshare数据获取2、Pandas数据处理3、Matplotl

pandas数据的合并concat()和merge()方式

《pandas数据的合并concat()和merge()方式》Pandas中concat沿轴合并数据框(行或列),merge基于键连接(内/外/左/右),concat用于纵向或横向拼接,merge用于... 目录concat() 轴向连接合并(1) join='outer',axis=0(2)join='o

shell脚本批量导出redis key-value方式

《shell脚本批量导出rediskey-value方式》为避免keys全量扫描导致Redis卡顿,可先通过dump.rdb备份文件在本地恢复,再使用scan命令渐进导出key-value,通过CN... 目录1 背景2 详细步骤2.1 本地docker启动Redis2.2 shell批量导出脚本3 附录总

分布式锁在Spring Boot应用中的实现过程

《分布式锁在SpringBoot应用中的实现过程》文章介绍在SpringBoot中通过自定义Lock注解、LockAspect切面和RedisLockUtils工具类实现分布式锁,确保多实例并发操作... 目录Lock注解LockASPect切面RedisLockUtils工具类总结在现代微服务架构中,分布

Java使用Thumbnailator库实现图片处理与压缩功能

《Java使用Thumbnailator库实现图片处理与压缩功能》Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应... 目录1. 图片处理库Thumbnailator介绍2. 基本和指定大小图片缩放功能2.1 图片缩放的

Oracle查询表结构建表语句索引等方式

《Oracle查询表结构建表语句索引等方式》使用USER_TAB_COLUMNS查询表结构可避免系统隐藏字段(如LISTUSER的CLOB与VARCHAR2同名字段),这些字段可能为dbms_lob.... 目录oracle查询表结构建表语句索引1.用“USER_TAB_COLUMNS”查询表结构2.用“a

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我