实现 malloc() 和 free() — 将元数据添加到内存块

实现 malloc() 和 free() — 将元数据添加到内存块

这篇文章是关于实现 malloc() 和 free() 函数的系列文章的一部分。之前,我们实现了一种相当简单的方法,几乎​​不释放任何内存:一个指针指向最后分配的块,使 free() 能够释放它,但只能释放它。

更好的选择是让最后一个块指向倒数第二个块,倒数第二个块指向倒数第三个块,依此类推,形成一个链表。为了实现这一点,我们创建一个结构体作为块的标题,其中包含指向前一个块的指针:

typedef 结构头 {  结构头*前一个;标题;

此外,指向最后一个块的指针,以前是 void*,现在是 Header* 类型:

标题*最后= NULL;

为了使用这些标头,abmalloc() 会保留足够的内存来存储标头和请求的大小:

void *abmalloc(size_t 大小) {  标头 *header = sbrk(sizeof(标头) + 大小);

通过这种方式,我们使用块的开头来存储必要的信息,例如指向新块之前最后分配的块的指针:

 标题->上一个 = 最后一个;

然后,我们更新最后一个指向新区块:

 最后 = 标题;

最后,我们返回一个指向用户可以使用的内存的指针。由于 header 指向元数据,我们不能简单地返回它。否则,当用户使用指针时,所有头信息都会被覆盖!相反,我们返回一个指向标题后面的指针。这个指针很容易计算:它是 header 的内存地址加上 header 的大小:

 返回标头 + 1;}

注意我们如何将 header 指针加 1。由于指针类型是 Header*,所以增量实际上是 Header 结构体的字节数,而不仅仅是一个字节。指针的类型与指针运算非常相关。

现在我们的内存块一开始就有元数据,我们在释放时需要考虑到这一点。 free() 接收的指针不是指向块的开头,而是指向用户可用的内存。因此,我们需要从用户传递的指针找到块的开始。没有什么是一点指针算术不能解决的:

void abfree(void *ptr) {  标头 *标头 = (标头*) ptr - 1;

如果 header 指向最后分配的块,则前一个块将成为最后一个。这种情况下,我们可以通过brk()将堆中的内存返回给操作系统:

 if (标题==最后){    最后=标题->上一个;    brk(标头);  }}

这是我们的新 malloc() 和 free() 函数:

typedef 结构头 {   结构头*前一个; 标题; 标头*最后= NULL; 无效* abmalloc(size_t大小){   标头 *header = sbrk(sizeof(标头) + 大小);   标题->上一个=最后一个;   最后=标题;   返回标头+1; } 无效 abfree(无效 *ptr) {   标头 *标头 = (标头*) ptr - 1;   如果(标题==最后){     最后=标题->上一个;     brk(标头);   } }

abmalloc() 和 abfree() 现在可能会稍微提高内存效率,但也不会高很多。动态分配的内存很少像堆栈一样工作,其中最旧的块总是首先被释放。在下一篇文章中,我们将看到如何使用不再使用的旧块的内存。

(这篇文章最初发布为“实现 malloc() 和 free() — 将元数据添加到暂停怀疑中的内存块。”

以上就是实现 malloc() 和 free() — 将元数据添加到内存块的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1455343.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月18日 07:41:06
下一篇 2025年12月18日 07:41:22

相关推荐

  • 在JSDoc中定义具有固定属性和任意额外属性的对象类型

    在JSDoc中定义具有固定属性和任意额外属性的对象类型是一个常见的需求,它允许开发者为数据结构指定核心字段,同时保留未来扩展的灵活性。本文旨在解决JSDoc中如何描述一种对象类型,该类型既包含一组强制性的固定属性,又允许添加任意数量的其他未预定义属性。我们将探讨两种主要方法:使用@property …

    2025年12月21日
    000
  • JSDoc中定义包含固定属性和任意扩展属性的对象类型

    本文探讨了在jsdoc中定义具有固定强制属性和任意附加属性的对象类型的方法。通过介绍从使用`*`通配符属性到结合交叉类型以及嵌入`object.`语法的多种技术,提供了实用的代码示例,旨在帮助开发者在javascript项目中实现类型定义的灵活性与严谨性。 在JavaScript项目中,使用JSDo…

    2025年12月21日
    000
  • JSDoc中定义具有固定属性和任意扩展属性的对象类型

    本教程旨在指导开发者如何在jsdoc中精确描述一种对象类型,该类型既包含明确定义的强制性属性,又允许灵活地添加任意数量的额外属性。文章将深入探讨多种实现策略,包括通配符属性、交叉类型`object.`的运用,并通过代码示例展示如何构建健壮且可扩展的类型定义,从而有效避免类型检查错误,提升javasc…

    2025年12月21日
    000
  • JS注解怎么标注交叉类型_ JS交叉类型参数的注解方法与示例

    交叉类型指同时具备多个类型的属性和方法,如 User & Admin 要求值包含两个类型的全部成员,可通过 JSDoc 的 @typedef 和 {T & U} 语法模拟实现,用于变量或参数注解以确保结构完整。 在JavaScript中,严格来说并没有“交叉类型”这一概念,这是Typ…

    2025年12月21日
    000
  • JS注解怎么和TypeScript结合_ JS注解在TypeScript环境下的应用

    TypeScript 支持通过配置 allowJs 和 checkJs 在 JavaScript 文件中识别 JSDoc 注解并进行类型检查,可在混合项目中提升类型安全;常见用法包括 @type、@param、@returns 和 @typedef,能为变量、函数参数等提供类型信息,支持与 .ts …

    2025年12月21日
    000
  • 如何用Node.js构建一个GraphQL API服务器?

    使用 Apollo Server 可快速构建 Node.js GraphQL 服务器,先初始化项目并安装 express、apollo-server-express 和 graphql 依赖,接着定义 User 类型和查询的 schema,编写返回模拟数据的解析器,然后在 Express 应用中启动…

    2025年12月20日
    000
  • 在Apollo Server中集成Neo4j图数据并正确返回关联节点

    本文详细介绍了如何在Apollo Server中结合Neo4j数据库,通过GraphQL查询并正确映射和返回中心节点及其关联节点。我们将探讨GraphQL模式定义、Neo4j数据查询以及Apollo Server解析器(Resolver)的实现细节,特别是如何处理嵌套的关联节点数据,确保数据结构与G…

    2025年12月20日
    000
  • 在 Apollo Server 中使用 WebSocket 获取 Context

    本文档旨在指导开发者在使用 Apollo Server 搭建 GraphQL 服务时,如何通过 WebSocket 连接获取请求的 Context 信息,包括身份验证 Token 等。我们将详细介绍配置步骤,并提供示例代码,帮助你理解如何在 WebSocket 环境下正确地传递和使用 Context…

    2025年12月20日
    000
  • 使用 JSDoc 注释泛型函数时 TypeScript 报错问题解析

    本文深入探讨了在使用 JSDoc 注释泛型函数时,@type 和 @param/@return 表现不同的原因,并提供了使用 @typedef 解决相关问题的方案。通过具体示例和代码片段,帮助开发者理解 TypeScript 如何解析 JSDoc 注释中的泛型类型,并避免在使用过程中可能遇到的错误。…

    2025年12月20日
    000
  • TypeScript类型声明与枚举:避免循环依赖的最佳实践

    本文探讨了在TypeScript项目中使用类型声明文件(.d.ts)与枚举时可能出现的循环依赖问题。当实现文件导入声明类型,而声明文件又反过来导入实现文件中的枚举时,会形成循环。文章提供了两种解决方案:将枚举提取到独立模块,或更推荐地,利用TypeScript的类型系统替代传统枚举,通过类型字面量和…

    2025年12月20日
    000
  • 使用JavaScript构建控制台版扫雷游戏教程

    本教程旨在指导开发者使用纯JavaScript在VS Code控制台中构建一个基础的扫雷游戏。文章将详细阐述游戏的数据结构设计、状态初始化、游戏板渲染、用户交互处理、胜负判断逻辑以及主游戏循环的构建。通过分步指导和代码示例,帮助读者理解如何将复杂的游戏逻辑分解为可管理的模块,并提供错误处理与性能优化…

    2025年12月20日
    000
  • 使用JavaScript构建控制台版扫雷游戏:从数据结构到游戏循环

    本教程将指导您使用纯JavaScript在控制台中构建一个完整的扫雷游戏。我们将从设计核心数据结构开始,逐步实现游戏状态初始化、棋盘渲染、用户交互处理(开采与标记)、胜负判断逻辑,并整合所有模块形成一个可玩的循环。通过本教程,您将掌握构建命令行游戏的系统化方法。 扫雷是一款经典的益智游戏,其核心逻辑…

    2025年12月20日
    000
  • JS如何实现请求合并

    请求合并的核心是通过延迟和聚合机制将多个相似请求整合为一次通信,以提升性能和用户体验;2. 实现方式包括构建缓冲队列、设置定时器调度、聚合请求数据并分发响应结果;3. 适用场景有列表批量操作、组件数据依赖聚合、实时搜索、埋点上报和数据预加载;4. 主要挑战在于状态管理、错误处理粒度、请求兼容性、后端…

    2025年12月20日
    100
  • js中if条件里能写注释吗

    是的,javascript 的 if 条件中可以写注释。1. 注释会被 javascript 引擎忽略,不影响代码执行;2. 支持单行注释(//)和多行注释(/…/);3. 在复杂条件中合理使用注释可提升可读性,如解释条件目的、分解逻辑、配合格式化代码;4. 注释过多不会影响性能,但应注…

    2025年12月20日 好文分享
    100
  • JSDOC:您向JavaScript添加类型的秘密武器(没有完整的打字稿大修)

    typescript为javascript添加静态类型,有助于尽早发现错误并简化大型代码库的管理。但全面迁移到typescript有时难度很大。这时,jsdoc就派上用场了,它允许您在不进行全面重构的情况下,获得静态类型系统的大部分优势。 JSDoc的强大之处在于它不仅仅是代码注释。通过@typed…

    2025年12月19日
    000
  • 让 JavaScript 更有趣的技巧

    编码可能是最有价值和最具创造性的工作之一,但说实话,它有时也可能让人不知所措、失去动力,甚至完全令人沮丧。多年来,我个人一直在与无聊、任务不堪重负和完美主义兔子洞作斗争。无论您是在从事业余项目、与团队合作还是应对专业挑战,这些技巧都旨在帮助您使编码变得更易于管理、更高效,而且最重要的是,更有趣。虽然…

    好文分享 2025年12月19日
    000
  • jsDoc 布道

    太长了; 使用遗留代码库 – 我们中的许多人无法一次又一次地躲避 – 让我尝试使用 jsdoc 而不是 typescript。我必须揭露令人惊讶的真相! 首先让我们清理一下: jsdoc 或 ts 只是意味着在开发人员时间下(包括稍后审查、重用、在任何环境中查看该代码:git…

    2025年12月19日
    000
  • jsDoc npm 模块任务

    目前我正在工作/维护遗留的 js/react 应用程序,没有办法重新工作到 typesript,这就是为什么我打开 jsdoc 作为 js 现有的开发时类型系统。 太长了; typescript npm 模块由 jsdoc 制作,useduck 在 70loc 下带回了 redux 的黄金时代。该模…

    2025年12月19日
    000
  • C++ size_t是什么类型_C++平台无关的内存大小类型解析

    size_t是C++中用于表示内存大小的无符号类型,定义于等头文件,源自C语言,实际为unsigned long或类似类型的别名,确保跨平台可移植性,常用于sizeof结果、数组下标、标准库函数参数及内存操作,避免整数溢出与类型不匹配问题。 size_t 是 C++ 中用于表示对象大小或内存相关数量…

    2025年12月19日
    000
  • C++的ABI稳定性为什么重要?C++库开发与版本管理【底层接口】

    c++kquote>ABI稳定性决定C++库跨版本复用的安全性,涉及链接后运行时崩溃与数据错乱风险;因缺乏统一标准,编译器、版本及选项差异易导致虚表错乱、内存踩踏、STL传参误读、异常捕获失败和RTTI失效;需通过PIMPL、C接口封装、固定布局、符号版本控制及工具检测等手段保障。 ABI稳定…

    2025年12月19日
    000

发表回复

登录后才能评论
关注微信