技术宅的结界

 找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 227|回复: 2
收起左侧

【C】简单的malloc和free的实现

[复制链接]

7

主题

11

帖子

261

积分

用户组: 中·技术宅

UID
6266
精华
5
威望
37 点
宅币
121 个
贡献
30 次
宅之契约
0 份
在线时间
5 小时
注册时间
2020-9-26
发表于 2020-10-26 14:41:39 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有帐号?立即注册→加入我们

x
这里简单实现了cstdlib的动态内存管理函数malloc、calloc、realloc和free
大致原理是先申请一个数组作为内存空间,然后使用链表连接每个申请的内存块。如果要释放内存,就从链表中移除相应的内存块。
在没有动态内存管理的环境中,以下代码能派上用场替代malloc函数等。
使用前需要先调用mpkInitMemory函数。
这是头文件:
[C] 纯文本查看 复制代码
#ifndef _MEMPKG_H_
#define _MEMPKG_H_

#include <stddef.h> /* Using type size_t. */

typedef unsigned char UCHART, * PUCHAR;

typedef struct st_BLOCK_HEADER
{
	struct st_BLOCK_HEADER * pnext;
	PUCHAR pblock;
	size_t size;
} BLOCK_HEADER, * P_BLOCK_HEADER;

#define MEM_SIZ (8192) /* Alter this macro to control the size of a heap. */

void   mpkInitMemory(void);
void * memcpy       (void *       dst, void *       src, size_t size);
void * memset       (void *       s,   int          c,   size_t n);
void * malloc       (size_t       size);
void   free         (void *       ptr);
void * realloc      (void *       ptr, size_t       size);
void * calloc       (size_t       n,   size_t       size);
int    memcmp       (const void * s1,  const void * s2,  size_t n);

#define memmove(dst, src, size) memcpy(dst, src, size)

#endif

源文件:
[C] 纯文本查看 复制代码
#include "mempkg.h"

UCHART volatile array[MEM_SIZ]; /* Create a linear address space. */

const PUCHAR volatile pmem = array;

volatile P_BLOCK_HEADER phead = NULL; /* This is the header pointer of block chain. */

/* Invoke this function before you use any function of this package.
 */
void mpkInitMemory(void)
{
	phead = (P_BLOCK_HEADER)pmem;
	phead->pblock = pmem + sizeof(BLOCK_HEADER);
	phead->pnext = (P_BLOCK_HEADER)(pmem + MEM_SIZ - sizeof(BLOCK_HEADER));
	phead->size = 0;
	phead->pnext->pblock = pmem + MEM_SIZ;
	phead->pnext->pnext = NULL;
	phead->pnext->size = 0;
}

void * memcpy(void * dst, void * src, size_t size)
{
	char * sc1;
	const char * sc2;
	sc1 = dst;
	sc2 = src;
	if (sc2 < sc1 && sc1 < sc2 + size)
		for (sc1 += size, sc2 += size; 0 < size; --size)
			*--sc1 = *--sc2;
	else
		for (; 0 < size; --size)
			*sc1++ = *sc2++;
	return dst;
}

void * memset(void * s, int c, size_t n)
{
	const UCHART uc = c;
	unsigned char * su;
	for (su = s; 0 < n; ++su, --n)
		*su = uc;
	return s;
}

void * malloc(size_t size)
{
	if (size > 0)
	{
		P_BLOCK_HEADER pnode, pnew;
		for (pnode = phead; NULL != pnode; pnode = pnode->pnext)
		{
			if (pnode->pnext != NULL)
			{	/* Test available space for the new block. */
				if (pnode->pnext->pblock - sizeof(BLOCK_HEADER) - pnode->pblock - pnode->size >=
					size + sizeof(BLOCK_HEADER))
				{
					pnew = (P_BLOCK_HEADER)(pnode->pblock + pnode->size);
					/* Initialize the new block header and assign new block. */
					pnew->pblock = pnode->pblock + pnode->size + sizeof(BLOCK_HEADER);
					pnew->size = size;
					pnew->pnext = pnode->pnext;
					pnode->pnext = pnew;
					return pnew->pblock;
				}
			}
			else
				break;
		}
	}
	return NULL;
}

void free(void * ptr)
{	/* Preserve the tail and header block structure. */
	if (pmem == ptr || pmem + MEM_SIZ == ptr)
		return;
	if (NULL != ptr)
	{
		P_BLOCK_HEADER pnode;
		for (pnode = phead; NULL != pnode; pnode = pnode->pnext)
		{
			if (NULL != pnode->pnext && ptr == pnode->pnext->pblock)
			{
				pnode->pnext = pnode->pnext->pnext;
				return;
			}
		}
	}
	return;
}

void * realloc(void * ptr, size_t size)
{	/* Preserve the tail and header block structure. */
	if (pmem == ptr || pmem + MEM_SIZ == ptr)
		return NULL;
	if (NULL == ptr && size > 0)
		return malloc(size);
	else if (size > 0)
	{
		P_BLOCK_HEADER pnode;
		for (pnode = phead; NULL != pnode; pnode = pnode->pnext)
		{
			if (NULL != pnode->pnext && ptr == pnode->pnext->pblock)
			{
				if (size == pnode->pnext->size)
					return ptr;
				else if (pnode->pnext->pnext->pblock - sizeof(BLOCK_HEADER) - pnode->pblock - pnode->size >=
					size + sizeof(BLOCK_HEADER))
				{
					pnode->pnext->size = size;
					return ptr;
				}
				else
				{
					void * newptr = malloc(size);
					if (NULL != newptr)
					{
						memcpy(newptr, ptr, pnode->pnext->size);
						free(ptr);
					}
					return newptr;
				}
			}
		}
	}
	return NULL;
}

void * calloc(size_t n, size_t size)
{
	void * rtn = malloc(size * n);
	memset(rtn, 0, size * n);
	return rtn;
}

int memcmp(const void * s1, const void * s2, size_t n)
{
	PUCHAR su1, su2;
	for (su1 = s1, su2 = s2; 0 < n; ++su1, ++su2, --n)
		if (*su1 != *su2)
			return *su1 < *su2 ? -1 : 1;
	return 0;
}

评分

参与人数 1威望 +5 宅币 +10 贡献 +5 收起 理由
0xAA55 + 5 + 10 + 5 是否考虑支持多线程调用?

查看全部评分

本帖被以下淘专辑推荐:

回复

使用道具 举报

1072

主题

2492

帖子

6万

积分

用户组: 管理员

一只技术宅

UID
1
精华
223
威望
420 点
宅币
20164 个
贡献
41913 次
宅之契约
0 份
在线时间
1908 小时
注册时间
2014-1-26
发表于 2020-10-27 00:27:37 | 显示全部楼层
一种裸机上管理内存的感觉,让我想到了在DOS年代,捅穿A20地址线,然后写16 MB内存的一些DOS游戏。

但,像STM32这样的单片机上,然后像STM32CubeIDE这样的开发环境提供的malloc其实是静态分配地址,就像一个宏,它给你局部起了一个static char mem[size];然后这块内存妥妥地进入了链接器脚本的.bss段。对应的,单片机上的free是没有任何行为的。

另外,现在的桌面机或者服务器环境,我为了实现高频的内存分配释放的效果,写过内存池,然后感觉一个比较大的难点是如何实现多线程环境下,能尽可能不锁住线程,实现高效的内存分配释放。

7

主题

11

帖子

261

积分

用户组: 中·技术宅

UID
6266
精华
5
威望
37 点
宅币
121 个
贡献
30 次
宅之契约
0 份
在线时间
5 小时
注册时间
2020-9-26
 楼主| 发表于 2020-10-27 14:01:26 | 显示全部楼层
这段代码还有个缺点就是容易形成内存碎片,本来想实现一个伙伴系统的无奈功夫不到家没有实现成功。
在多线程环境下这段代码必须加锁,不然内存会被写乱。
另外,楼上可以参考一下glibc的malloc来获得灵感。

本版积分规则

QQ|申请友链||Archiver|手机版|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图  

GMT+8, 2020-11-28 04:42 , Processed in 0.092538 second(s), 33 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表