本文目录
文章对应视频教程:
看下面。
以为很难,其实简单的动态内存管理(从零手写)-概念篇01
1、动态内存管理过程
绿色矩形代表一片连续内存。
把内存分配出去,就是动态内存申请的过程。
程序不再使用内存,退还给系统内存,就是动态内存的回收。
程序的申请与回收就是动态内存的管理。
是不是很简单~~~
2、什么是动态内存,什么是静态内存?
动态内存和静态内存的区别主要在于内存分配和管理的时机和方式。
静态内存:
• 分配时机:在编译时分配,内存分配大小在编译时确定。
• 作用范围:通常用于全局变量、静态变量和常量。
• 生存期:从程序开始运行到程序结束。
• 优点:分配和释放内存的开销较低,不存在碎片化问题。
• 缺点:内存使用不够灵活,难以处理动态变化的需求。
动态内存:
• 分配时机:在运行时分配,内存分配大小在运行时确定。
• 作用范围:通常用于堆内存,程序运行时通过函数(如 malloc、calloc、realloc、free)进行管理。
• 生存期:由程序员控制,可以在运行时任意分配和释放。
• 优点:内存使用灵活,可以根据实际需要分配合适大小的内存,适合处理动态变化的需求。
• 缺点:需要显式管理内存,容易引发内存泄漏和碎片化问题。
3、为什么要使用动态内存?动态内存能解决什么问题?
3.1 为什么要使用动态内存?动态内存能解决什么问题?
- 灵活性:可以在程序运行时根据实际需求分配合适大小的内存,适应动态变化的情况。
- 内存效率:避免了静态分配中可能的内存浪费,减少了内存的占用,提高了内存的利用率。
- 数据结构:支持复杂数据结构(如链表、树、图等)的实现,这些数据结构需要在运行时动态分配内存。
- 程序设计:在一些设计模式和算法中,动态内存分配是必要的,以便处理不确定的数据量和变化的需求。
3.2 动态内存能解决的问题
• 变长数据:处理大小在编译时无法确定的数据,如用户输入、文件内容等。
• 复杂数据结构:实现需要动态调整大小的数据结构,如链表、树、哈希表等。
• 模块化和复用:在模块化设计和库函数中,动态内存分配使得函数更加通用,能够处理不同大小的数据。
4、实现动态内存管理需要实现哪些功能
4.1 实现动态内存管理通常需要以下基本功能
- 内存分配:从内存池或堆中分配一块指定大小的内存,并返回指向该内存块的指针(如 malloc)。
- 内存释放:将不再需要使用的内存块返回给内存池或堆,以便再次使用(如 free)。
- 内存重分配:调整已分配内存块的大小,可能会移动内存块以适应新的大小(如 realloc)。
- 边界检查和安全性:防止内存越界访问,检测和处理非法的内存操作。
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