本文目录
文章对应视频教程:
暂无,可以关注我的B站账号等待更新。
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)
{
ff->next = NULL;
}
ff->last = fh;
fh->next = ff;
}
else if(ff < fm_alt->free_head && (void*)ff >= fm_alt->mem_start)
{
fm_free_t *fh = fm_alt->free_head;
fh->last = ff;
ff->next = fh;
ff->last = NULL;
fm_alt->free_head = ff;
}
else
{
return -1;
}
ff->start_magic = FM_FREE_MAGIC;
ff->bsize = size - (size % FMPOOL_PAGE_SIZE);
ff->end_magic = FM_FREE_MAGIC;
return ff->bsize;
}
static int __add_used_block(void *p ,fm_size_t rsize,fm_size_t asize,char *name,fm_size_t line)
{
FM_ASSERT(p);
fm_used_t *fu = p;
if(!fm_alt->used_head)
{
fm_alt->used_head = fu;
fu->last = NULL;
fu->next = NULL;
}
else if(fu > fm_alt->used_head)
{
fm_used_t *fh = fm_alt->used_head;
while (fh->next)
{
if(fh < fu && (void*)fu < fh->next)
{
fm_used_t *fh_n = fh->next;
fh_n->last = fu;
fu->next = fh_n;
break;
}
if(fu == fh->next)
{
return -2;
}
fh = fh->next;
}
if(!fh->next)
{
fu->next = NULL;
}
fu->last = fh;
fh->next = fu;
}
else if(fu < fm_alt->used_head && (void*)fu >= fm_alt->mem_start)
{
fm_used_t *fh = fm_alt->used_head;
fh->last = fu;
fu->next = fh;
fu->last = NULL;
fm_alt->used_head = fu;
}
else
{
return -1;
}
fu->start_magic = FM_USED_MAGIC;
fu->real_size = rsize;
fu->align_size = asize;
fu->name = name;
fu->line = line;
fu->end_magic = FM_USED_MAGIC;
return fu->real_size;
}
static int __delete_free_block(void *p)
{
__fm_check_free_magic(p);
fm_free_t *ff = p;
if(ff == fm_alt->free_head)
{
fm_free_t *fh = ff->next;
if(fh)
{
fh->last = NULL;
}
fm_alt->free_head = fh;
}
else if(ff > fm_alt->free_head)
{
fm_free_t *fp = ff->last;
if(fp)
{
fp->next = ff->next;
}
fp = ff->next;
if(fp)
{
fp->last = ff->last;
}
}
else
{
return -1;
}
int ret = ff->bsize;
memset(ff,0,sizeof(fm_free_t));
return ret;
}
static int __delete_used_block(void *p)
{
__fm_check_used_magic(p);
fm_used_t *fu = p;
if(fu == fm_alt->used_head)
{
fm_used_t *fh = fu->next;
if(fh)
{
fh->last = NULL;
}
fm_alt->used_head = fh;
}
else if(fu > fm_alt->used_head)
{
fm_used_t *fp = fu->last;
if(fp)
{
fp->next = fu->next;
}
fp = fu->next;
if(fp)
{
fp->last = fu->last;
}
}
else
{
return -1;
}
int ret = fu->align_size;
memset(fu,0,sizeof(fm_used_t));
return ret;
}
int fm_init(void)
{
// page must align the aligned num
FM_ASSERT(FMPOOL_PAGE_SIZE % FMPOOL_ALIGNED == 0);
int ret = __fm_mutex_init();
if(ret < 0)
{
FM_PRINT("fm_mutex init error\r\n");
return -1;
}
__fm_mutex_take();
fm_size_t fm_alt_size = sizeof(fm_allocator_t);
fm_alt_size = (fm_alt_size % FMPOOL_PAGE_SIZE)?(fm_alt_size + (FMPOOL_PAGE_SIZE - (fm_alt_size % FMPOOL_PAGE_SIZE) )):fm_alt_size;
fm_alt = (void*)fmpool;
fm_alt->mem_start = (void*)(fmpool+fm_alt_size);
fm_alt->all_size = FMPOOL_SIZE;
fm_alt->used_size = fm_alt_size;
fm_alt->max_used_size = fm_alt_size;
fm_alt->free_head = NULL;
fm_alt->used_head = NULL;
__add_free_block( fm_alt->mem_start,FMPOOL_SIZE - fm_alt_size);
__fm_mutex_release();
return 0;
}
void *__fm_malloc_with_info(fm_size_t size,char *name,fm_size_t line)
{
if(size == 0)
{
return NULL;
}
fm_size_t align_size = __fm_align(size);
fm_free_t *suit_ff = NULL;
int ret = __fm_mutex_take();
if(ret < 0 )
{
return NULL;
}
fm_free_t *ff = fm_alt->free_head;
while (ff)
{
if(ff->bsize == align_size)
{
suit_ff = ff;
break;
}
else if(ff->bsize > align_size)
{
if(suit_ff)
{
suit_ff = (suit_ff->bsize > ff->bsize)?ff:suit_ff;
}
else
{
suit_ff = ff;
}
}
ff = ff->next;
}
if(!suit_ff)
{
__fm_mutex_release();
return NULL;
}
if(suit_ff->bsize == align_size)
{
__delete_free_block(suit_ff);
__add_used_block(suit_ff,size,align_size,name,line);
}
else
{
fm_free_t *add_ff = FM_OFFSET(suit_ff,align_size);
fm_size_t add_size = suit_ff->bsize - align_size;
__delete_free_block(suit_ff);
__add_free_block(add_ff,add_size);
__add_used_block(suit_ff,size,align_size,name,line);
}
fm_alt->used_size += align_size;
if(fm_alt->max_used_size < fm_alt->used_size)
{
fm_alt->max_used_size = fm_alt->used_size;
}
__fm_mutex_release();
return FM_OFFSET_USER_AREA(suit_ff);
}
void *fm_malloc(fm_size_t size)
{
return __fm_malloc_with_info(size,NULL,0);
}
static void* __merge_next_free_bolck(void *p)
{
FM_ASSERT(p);
fm_free_t *ff = p;
fm_free_t *ff_n = ff->next;
if(ff_n && ff_n == FM_OFFSET(ff,ff->bsize))
{
ff->next = ff_n->next;
ff->bsize += ff_n->bsize;
fm_free_t *ff_nn = ff_n->next;
if(ff_nn)
{
ff_nn->last = ff;
}
memset(ff_n,0,sizeof(fm_free_t));
return ff;
}
return NULL;
}
static void __merge_free_bolck(void *p)
{
FM_ASSERT(p);
fm_free_t *ff = p;
fm_free_t *ffm = __merge_next_free_bolck(ff);
if(ff->last)
{
__merge_next_free_bolck(ff->last);
}
}
void fm_free(void *ptr)
{
FM_ASSERT(ptr);
__fm_mutex_take();
fm_used_t *fu = FM_OFFSET_USED_HEAD(ptr);
__fm_check_used_magic(fu);
fm_size_t free_size = fu->align_size;
__delete_used_block(fu);
__add_free_block(fu,free_size);
__merge_free_bolck(fu);
fm_alt->used_size -= free_size;
__fm_mutex_release();
}
void *fm_calloc(fm_size_t nmemb, fm_size_t size)
{
fm_size_t msize = nmemb*size;
void *new = fm_malloc(msize);
if(new)
{
memset(new,0,msize);
}
return new;
}
void *fm_realloc(void *ptr, fm_size_t size)
{
if (!ptr)
{
return fm_malloc(size);
}
if(ptr && size == 0)
{
fm_free(ptr);
return NULL;
}
fm_used_t *fu = FM_OFFSET_USED_HEAD(ptr);
__fm_check_used_magic(fu);
if(size <= fu->align_size)
{
fu->real_size = size;
return ptr;
}
void *new = fm_malloc(size);
if(new)
{
memcpy(new,ptr,fu->real_size);
fm_free(ptr);
}
else
{
return NULL;
}
return new;
}
static int __fm_free_mem_check(void)
{
fm_free_t *ff = fm_alt->free_head;
fm_size_t free_size = 0;
while (ff)
{
if(ff->start_magic != FM_FREE_MAGIC || ff->end_magic != FM_FREE_MAGIC)
{
FM_PRINT("bad free boclk 0x%p %4d\r\n",ff,ff->bsize);
return -1;
}
free_size += ff->bsize;
ff = ff->next;
}
if(free_size != (fm_alt->all_size - fm_alt->used_size))
{
FM_PRINT("free boclk size %6d != %6d\r\n", \
free_size,fm_alt->all_size - fm_alt->used_size);
return -2;
}
return 0;
}
static int __fm_used_mem_check(void)
{
fm_used_t *fu = fm_alt->used_head;
fm_size_t used_size = 0;
while (fu)
{
if(fu->start_magic != FM_USED_MAGIC || fu->end_magic != FM_USED_MAGIC)
{
FM_PRINT("bad used boclk 0x%p %4d %4d %s:%d\r\n", \
fu,fu->real_size,fu->align_size,fu->name,fu->line);
return -1;
}
used_size += fu->align_size;
fu = fu->next;
}
fm_size_t fm_alt_size = sizeof(fm_allocator_t);
fm_alt_size = (fm_alt_size % FMPOOL_PAGE_SIZE)? \
(fm_alt_size + (FMPOOL_PAGE_SIZE - (fm_alt_size % FMPOOL_PAGE_SIZE) )):fm_alt_size;
used_size += fm_alt_size;
if(used_size != fm_alt->used_size)
{
FM_PRINT("used boclk size %6d != %6d\r\n", \
used_size,fm_alt->used_size);
return -2;
}
return 0;
}
int fm_memory_check(void)
{
int ret = __fm_used_mem_check();
ret += __fm_free_mem_check();
return ret;
}
static void __fm_print_allocator_info(void)
{
FM_PRINT("-----------------------------------------------------\r\n");
FM_PRINT("info addr\r\n");
FM_PRINT("fmpool 0x%p\r\n",fmpool);
FM_PRINT("mem_start 0x%p\r\n",fm_alt->mem_start);
FM_PRINT("free_head 0x%p\r\n",fm_alt->free_head);
FM_PRINT("used_head 0x%p\r\n",fm_alt->used_head);
}
static void __fm_print_memory_info(void)
{
FM_PRINT("-----------------------------------------------------\r\n");
FM_PRINT("memory per used/all\r\n");
FM_PRINT("free %5.2f%% %d/%d\r\n", \
100.-(float)fm_alt->used_size/fm_alt->all_size*100., \
fm_alt->all_size - fm_alt->used_size,fm_alt->all_size);
FM_PRINT("used %5.2f%% %d/%d\r\n", \
(float)fm_alt->used_size/fm_alt->all_size*100., \
fm_alt->used_size,fm_alt->all_size);
FM_PRINT("max_used %5.2f%% %d/%d\r\n", \
(float)fm_alt->max_used_size/fm_alt->all_size*100., \
fm_alt->max_used_size,fm_alt->all_size);
}
static void __fm_print_free_info(void)
{
FM_PRINT("-----------------------------------------------------\r\n");
FM_PRINT("info addr len\r\n");
fm_free_t *ff = fm_alt->free_head;
while (ff)
{
FM_PRINT("free 0x%p %4d\r\n",ff,ff->bsize);
ff = ff->next;
}
}
static void __fm_print_used_info(void)
{
FM_PRINT("-----------------------------------------------------\r\n");
FM_PRINT("info addr rlen alen file:line\r\n");
fm_used_t *fu = fm_alt->used_head;
while (fu)
{
FM_PRINT("used 0x%p %4d %4d %s:%d\r\n", \
fu,fu->real_size,fu->align_size,fu->name,fu->line);
fu = fu->next;
}
}
void fm_print_all_info(void)
{
__fm_print_allocator_info();
__fm_print_memory_info();
__fm_print_used_info();
__fm_print_free_info();
}
fmpool.h
/**
* @file dmpool.h
* @author zhuxuanlin
* @brief
* @version 0.1
* @date 2024-06-20
*
* @copyright Copyright (c) 2024
*
*/
#ifndef __FMPOOL_H__
#define __FMPOOL_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "ck_config.h"
#include "assert.h"
typedef unsigned long fm_size_t;
typedef unsigned char fm_byte_t;
#define FM_ALIGNED __attribute__((aligned(FMPOOL_ALIGNED)))
#define FM_ASSERT(x) assert(x)
#define FMPOOL_SIZE (FMPOOL_ALL_SIZE * 1024)
#define FM_FREE_MAGIC 0x5A5A5A5Au
#define FM_USED_MAGIC 0xA5A5A5A5u
#define FM_OFFSET(x,off) (void*)((void*)(x)+(off))
#define FM_PRINT printf
/**
* @brief 空闲内存块的info
*
*/
typedef struct
{
fm_size_t start_magic;
void *last;
void *next;
fm_size_t bsize;
fm_size_t end_magic;
}fm_free_t FM_ALIGNED;
typedef struct
{
fm_size_t start_magic;
void *last;
void *next;
fm_size_t real_size;
fm_size_t align_size;
char *name;
fm_size_t line;
fm_size_t end_magic;
}fm_used_t FM_ALIGNED;
/**
* @brief 内存管理的info
*
*/
typedef struct
{
void *mem_start;
fm_size_t all_size;
fm_size_t used_size;
fm_size_t max_used_size;
fm_free_t *free_head;
fm_used_t *used_head;
}fm_allocator_t;
#define FM_OFFSET_USER_AREA(x) (void*)((void*)(x)+(sizeof(fm_used_t)))
#define FM_OFFSET_USED_HEAD(x) (void*)((void*)(x)-(sizeof(fm_used_t)))
void *__fm_malloc_with_info(fm_size_t size,char *name,fm_size_t line);
#define FM_MALLOC(x) __fm_malloc_with_info((x),__FILE__,__LINE__)
extern int fm_init(void);
extern void *fm_malloc(fm_size_t size);
extern void fm_free(void *ptr);
extern void *fm_calloc(fm_size_t nmemb, fm_size_t size);
extern void *fm_realloc(void *ptr, fm_size_t size);
extern int fm_memory_check(void);
extern void fm_print_all_info(void);
#ifdef __cplusplus
}
#endif
#endif /* __FMPOOL_H__ */
验证结果:
时间流逝、年龄增长,是自己的磨炼、对知识技术的应用,还有那不变的一颗对嵌入式热爱的心!
点赞o( ̄▽ ̄)d、关注(o)/~、评论(▽)!