实现 malloc() 和 free() — 分割大块

实现 malloc() 和 free() — 分割大块

上一篇文章探讨了内存块重用顺序对内存消耗的影响,并优化了函数以减少浪费。然而,另一个更严重的问题依然存在:一个巨大的内存块可能会占据多个小块本可利用的空间。例如,分配一大块内存,释放后,再分配两个更小的块:

void *ptr1 = abmalloc(128);void *ptr2 = abmalloc(8);abfree(ptr1);void *ptr3 = abmalloc(8);void *ptr4 = abmalloc(8);

登录后复制

这时,128字节的空闲块无法被8字节的请求利用,导致后续8字节块分配需要再次扩展堆,造成内存利用率低下。

解决这个问题,一种高效但复杂的方法是使用“bins”:按大小分组的块列表。另一种更简单的方案是将大块分割成更小的块。本文采用后者。

代码重构

首先,对代码进行轻微重构。header_new() 函数同时负责分配内存和初始化块头,这不利于代码的可读性和维护性。我们将它拆分成两个函数:

header_plug():将已初始化的块插入到前一个和下一个块之间。header_init():初始化块的元数据(大小和可用性)。

它们分别如下:

void header_init(header *header, size_t size, bool available) {    header->size = size;    header->available = available;}void header_plug(header *header, header *previous, header *next) {    header->previous = previous;    if (previous != NULL) {        previous->next = header;    }    header->next = next;    if (next != NULL) {        next->previous = header;    }}

登录后复制

header_new() 函数修改如下:

header *header_new(header *previous, size_t size, bool available) {    header *header = sbrk(sizeof(header) + size);    header_init(header, size, available);    header_plug(header, previous, NULL);    return header;}

登录后复制

(abmalloc() 函数中 last->previous->next = last; 这行可以删除,因为 header_plug() 现在负责处理此逻辑。)

分割内存块

接下来,实现 header_split() 函数。给定一个块头和所需最小大小,如果原始块足够大,则将其分割成两部分:

所需大小的块;剩余部分及其新的块头;

首先,检查块是否足够大:

header *header_split(header *header, size_t size) {    size_t original_size = header->size;    if (original_size >= size + sizeof(header)) {

登录后复制

如果足够大,则分割块。首先,减小当前块的大小:

        header->size = original_size - size - sizeof(header);

登录后复制

计算新块的指针:

        header *new_header = (header + 1) + header->size; // Corrected pointer calculation

登录后复制

初始化新块的头:

        header_init(new_header, size, true);

登录后复制

将新块连接到链表:

        header_plug(new_header, header, header->next);

登录后复制

如果原始块是最后一个块,更新 last 指针:

        if (header == last) {            last = new_header;        }

登录后复制

返回新块:

        return new_header;    } else {        return header;    }}

登录后复制

更新 abmalloc()

最后,修改 abmalloc() 函数,在找到可用块后,调用 header_split() 尝试分割它:

if (header->available && (header->size >= size)) {    header = header_split(header, size);    header->available = false;    return (void*)(header + 1); // Cast to void* for correct return type}

登录后复制

如果块可以分割,则返回新块;否则,返回原始块。

关于块分割的说明

需要注意的是,新块是在原始块的末尾创建的。虽然也可以在开头创建,但在末尾创建新块可以使新的空闲块更靠近旧块,提高下次 abmalloc() 调用的效率。

分割大块内存是改进内存管理的一步,但它也可能导致小块内存碎片化,从而导致更大的请求需要扩展堆。下一篇文章将探讨如何解决这个问题。

以上就是实现 malloc() 和 free() — 分割大块的详细内容,更多请关注【创想鸟】其它相关文章!

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

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2446414.html

(0)
上一篇 2025年3月3日 16:32:10
下一篇 2025年3月3日 16:32:26

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • 解析 C 中的命令行参数

    本文将演示如何使用C语言解析命令行参数。以下代码实现了一个简单的命令行参数解析器,能够处理文件路径、布尔标志和整数值。 #include #include #include #include // 定义结构体存储命令行参数typedef s…

    2025年3月3日
    100
  • DSA日介绍

    大家好! 我将开启一个专注于数据结构和算法 (DSA) 的博客系列。教程内容基于我的学习和经验。 我将使用 C 语言编写这些教程,并为 C 语言初学者提供入门教程。 虽然 DSA 可用 C、Java 或 Python 等语言实现, 但我选择…

    2025年3月3日
    200
  • 如何计算 CPU 百分比

    系统管理员经常面临一个棘手的问题:快速在机器上生成虚拟CPU负载。本文提供一种简单有效的解决方案,无需安装额外工具。 单核CPU负载: 最基础的方法是用C语言编写一个简单的无限循环程序。只需将以下代码保存为文件(例如,stressme.c)…

    2025年3月3日
    200
  • c++和c的语法区别 c和c++有什么区别

    C++和C的主要区别在于面向对象特性的加入,这使得C++更易于维护和扩展,但运行时开销也可能更高。C更精简高效,适合底层开发,但代码易于变得复杂。 C++和C:两种语言,两种世界 很多人问C++和C到底差在哪儿?简单说,C是C++的爸爸,但…

    2025年3月3日
    200
  • c和c#的区别和联系有哪些

    C和C#虽有类似之处,但截然不同:C是面向过程、手动内存管理、平台依赖的语言,用于系统编程;C#是面向对象、垃圾回收、平台独立的语言,用于桌面、Web应用和游戏开发。 C和C#:孪生兄弟,殊途同归? 很多初学者,甚至一些老手,都会被C和C#…

    2025年3月3日
    200
  • c上标3下标5怎么算 c上标3下标5算法教程

    C35 的计算本质上是组合数学,代表从 5 个元素中选择 3 个的组合数,其计算公式为 C53 = 5! / (3! * 2!),可通过循环避免直接计算阶乘以提高效率和避免溢出。另外,理解组合的本质和掌握高效的计算方法对于解决概率统计、密码…

    2025年3月3日
    200
  • distinct函数用法 distance函数c++用法教程

    std::unique 去除容器中的相邻重复元素,并将它们移到末尾,返回指向第一个重复元素的迭代器。std::distance 计算两个迭代器之间的距离,即它们指向的元素个数。这两个函数对于优化代码和提升效率很有用,但也需要注意一些陷阱,例…

    2025年3月3日
    200
  • c语言函数的执行顺序是什么

    C语言函数执行顺序遵循从上而下的原则,但优化器可能会对其进行调整。函数指针和回调函数的执行时机由调用函数控制。清晰易懂的代码、详尽注释和调试工具是避免执行顺序问题的关键。 C语言函数的执行顺序:潜伏的陷阱与高效的掌控 很多初学者,甚至一些有…

    2025年3月3日
    200
  • c语言函数的执行顺序有哪些

    C语言函数的执行顺序并非从上到下那么简单,而是受到多种因素影响,包括函数调用方式、递归、指针以及异步操作。函数调用栈决定了函数执行顺序,而调用方式、递归、指针函数和函数指针以及异步操作复杂化了这个过程,带来了灵活性但同时也增加了难以预测性。…

    2025年3月3日
    200
  • OPPO PKV110 手机证件照公示,电池额定容量 5640mAh

    12月13日,型号为“pkv110”的oppo新机现身工信部网站。根据公布的证件照,该机采用居中打孔屏设计,背面配备双摄镜头和led闪光灯,并印有“ai camera system”标识。 由于屏幕处于关闭状态,暂时无法判断边框宽度。手机右…

    2025年3月3日 互联网
    200

发表回复

登录后才能评论