用C语言手写动态内存管理


文章对应视频教程:

看下面。


点击图片或链接访问我的B站主页~~~

以为很难,其实简单的动态内存管理(从零手写)-概念篇01


1、动态内存管理过程

在这里插入图片描述
绿色矩形代表一片连续内存。
在这里插入图片描述
把内存分配出去,就是动态内存申请的过程。
在这里插入图片描述
程序不再使用内存,退还给系统内存,就是动态内存的回收。

程序的申请与回收就是动态内存的管理。
是不是很简单~~~

2、什么是动态内存,什么是静态内存?

动态内存和静态内存的区别主要在于内存分配和管理的时机和方式。
静态内存
• 分配时机:在编译时分配,内存分配大小在编译时确定。
• 作用范围:通常用于全局变量、静态变量和常量。
• 生存期:从程序开始运行到程序结束。
• 优点:分配和释放内存的开销较低,不存在碎片化问题。
• 缺点:内存使用不够灵活,难以处理动态变化的需求。
动态内存
• 分配时机:在运行时分配,内存分配大小在运行时确定。
• 作用范围:通常用于堆内存,程序运行时通过函数(如 malloc、calloc、realloc、free)进行管理。
• 生存期:由程序员控制,可以在运行时任意分配和释放。
• 优点:内存使用灵活,可以根据实际需要分配合适大小的内存,适合处理动态变化的需求。
• 缺点:需要显式管理内存,容易引发内存泄漏和碎片化问题。


3、为什么要使用动态内存?动态内存能解决什么问题?

3.1 为什么要使用动态内存?动态内存能解决什么问题?

  1. 灵活性:可以在程序运行时根据实际需求分配合适大小的内存,适应动态变化的情况。
  2. 内存效率:避免了静态分配中可能的内存浪费,减少了内存的占用,提高了内存的利用率。
  3. 数据结构:支持复杂数据结构(如链表、树、图等)的实现,这些数据结构需要在运行时动态分配内存。
  4. 程序设计:在一些设计模式和算法中,动态内存分配是必要的,以便处理不确定的数据量和变化的需求。

3.2 动态内存能解决的问题

• 变长数据:处理大小在编译时无法确定的数据,如用户输入、文件内容等。
• 复杂数据结构:实现需要动态调整大小的数据结构,如链表、树、哈希表等。
• 模块化和复用:在模块化设计和库函数中,动态内存分配使得函数更加通用,能够处理不同大小的数据。


4、实现动态内存管理需要实现哪些功能

4.1 实现动态内存管理通常需要以下基本功能

  1. 内存分配:从内存池或堆中分配一块指定大小的内存,并返回指向该内存块的指针(如 malloc)。
  2. 内存释放:将不再需要使用的内存块返回给内存池或堆,以便再次使用(如 free)。
  3. 内存重分配:调整已分配内存块的大小,可能会移动内存块以适应新的大小(如 realloc)。
  4. 边界检查和安全性:防止内存越界访问,检测和处理非法的内存操作。

4.2 常见问题及解决方法

内存泄漏(Memory Leak):
程序分配了内存但未能正确释放,导致内存不可用,随着时间的推移,内存泄漏会导致系统内存耗尽。
内存碎片(Memory Fragmentation):
频繁的内存分配和释放会导致内存不连续,碎片化问题严重时会导致无法找到足够大的连续内存块。
内存越界(Buffer Overflow/Underflow):
访问数组或内存块边界之外的内存,导致数据破坏或程序崩溃。


5、写一个简单的动态内存管理

首先将内存分为固定大小的内存块。
在这里插入图片描述
创建一个Used和一个Free的内存块的双向有序链表。将内存池中的两种内存块分别连接起来,方便管理。
在这里插入图片描述
设计一个动态内存管理的数据结构,用于管理整个内存池,包括Used、Free内存块的链表头储存,已经使用内存大小的储存等信息。
在这里插入图片描述
该动态内存管理支持多段内存同时管理、内存合并、最佳匹配申请、内存申请记录、内存溢出检测等功能。
实现这部分动态内存管理也很简单,代码如下:
fmpool.c

/**
 * @file dmpool.c
 * @author zhuxuanlin
 * @brief 
 * @version 0.1
 * @date 2024-06-20
 * 
 * @copyright Copyright (c) 2024
 * 
 */
#include "fmpool.h"
#include "string.h"
#include "stdio.h"

static fm_byte_t fmpool[FMPOOL_SIZE] FM_ALIGNED;
static fm_allocator_t *fm_alt;

#include <windows.h>
HANDLE hMutex;

static int __fm_mutex_init(void)
{
   
    #ifdef FMPOOL_MUTEX
        hMutex = CreateMutex(NULL,FALSE,NULL);
        if(hMutex == NULL)
        {
   
            FM_PRINT("create mutex error\r\n");
            return -1;
        }
        return 0;
    #else
        return 0;
    #endif 
}

static int __fm_mutex_take(void)
{
   
    #ifdef FMPOOL_MUTEX
        WaitForSingleObject(hMutex,INFINITE);
        return 0;
    #else
        return 0;
    #endif    
}

static int __fm_mutex_release(void)
{
   
    #ifdef FMPOOL_MUTEX
        ReleaseMutex(hMutex);
        return 0;
    #else
        return 0;
    #endif     
}

static fm_size_t __fm_align(fm_size_t size)
{
   
    size += sizeof(fm_used_t);
    return (size % FMPOOL_PAGE_SIZE)?(size + (FMPOOL_PAGE_SIZE - (size % FMPOOL_PAGE_SIZE) )):size;
}

static void __fm_check_free_magic(fm_free_t *ff)
{
   
    FM_ASSERT(ff);
    FM_ASSERT(fm_alt->mem_start <= (void*)ff);
    FM_ASSERT((fm_alt->mem_start + FMPOOL_SIZE) > (void*)ff);
    FM_ASSERT(ff->start_magic == FM_FREE_MAGIC);
    FM_ASSERT(ff->end_magic == FM_FREE_MAGIC);
}

static void __fm_check_used_magic(fm_used_t *fu)
{
   
    FM_ASSERT(fu);
    FM_ASSERT(fm_alt->mem_start <= (void*)fu);
    FM_ASSERT((fm_alt->mem_start + FMPOOL_SIZE) > (void*)fu);
    FM_ASSERT(fu->start_magic == FM_USED_MAGIC);
    FM_ASSERT(fu->end_magic == FM_USED_MAGIC);
}

static int __add_free_block(void *p ,fm_size_t size)
{
   
    FM_ASSERT(p);
    fm_free_t *ff = p;

    if(!fm_alt->free_head)
    {
   
        fm_alt->free_head = ff;
        ff->last = NULL;
        ff->next = NULL;
    }
    else if(ff > fm_alt->free_head)
    {
   
        fm_free_t *fh = fm_alt->free_head;
        while (fh->next)
        {
   
            if(fh < ff && (void*)ff < fh->next)
            {
   
                fm_free_t *fh_n = fh->next;
                fh_n->last = ff;
                ff->next = fh_n;
                break;
            }
            if(ff == fh->next)
            {
   
                return -2;
            }
            fh = fh->next;
        }
        if(!fh->next
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhuzhu、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值