C语言之内存动态管理(边界标识法)源码

 

1       概述.... 3

2       背景.... 3

3       工作机制.... 3

4       分配机制特点.... 3

5       应用场景.... 3

6       源码文件.... 4

6.1       MemAlloc.h. 4

6.2       MemAlloc.cpp. 4

7       数组接口函数使用说明.... 16

7.1       CreateHeap(). 16

7.2       DestroyHeap (). 17

7.3       AllocMem(). 17

7.4       FreeMem(). 18

8       demo.. 19

 

  1.  概述

本文讲述一种的内存动态管理机制:边界标识法。关于边界标识法大家有兴趣的话可以阅读清华计算机教材《数据结构》(作者:严蔚敏、吴伟民)第八章(动态存储管理)中第3节(边界标识法)。本文主要是针对从事后台服务器程序领域讲述这种内存分配机制的应用场景和优缺点。

 

2.背景

本文提出的内存分配管理策略是对清华计算机教材《数据结构》(作者:严蔚敏、吴伟民)第八章(动态存储管理)中第3节(边界标识法)示例代码的整理和封装。

 

3. 工作机制

应用程序首先调用mallo()函数预先分配出一块内存空间,然后在这个内存空间中使用边界标识法分配出应用程序需要的内存,内存释放时,会自动合并前后紧邻的空闲块,形成更大的空闲块。

 

4. 分配机制特点

该机制优点是:

  1. 可以根据需要分配任意大小的空间,不需要取整。
  2. 释放内存操作极快。

 

该机制缺点是:

1、长时间运行可能会产生大量碎片,导致内存分配的效率降低和内存的浪费。

 

  1.  应用场景

针对服务器程序应用场景:

1、需要连续内存空间。

2、分配内存大小范围大,从1个字节到上兆、几十兆。

3、分配的空间只是临时使用,用完就释放,不至于产生大量碎片。

另外:如果设计的软件对性能要求不高,也可以考虑使用此种内存分配机制。

 

5. 源码文件

 

5.1 MemAlloc.h

 


#ifndef MEMALLOC_H
#define MEMALLOC_H

typedef void* HANDLE;

HANDLE CreateHeap(int nHeapSize);
void DestroyHeap(HANDLE hHeap);
void* AllocMem(HANDLE hHeap, int nSize);
void FreeMem(HANDLE hHeap, void* pAddr);
int GetAddrSize(void* pAddr);
void FreeAllMem(HANDLE hHeap);

#endif

 

5.2  MemAlloc.cpp

 

#include "MemAlloc.h"
#include "TagShare.h"
#include <stdio.h>

static AllocTail* FootLoc(AllocNode* pHead)
{	
	return (AllocTail *)((char *)pHead + pHead->nSize - sizeof(AllocTail));
}

int GetSelfUplink(AllocNode* p)
{
	return ((AllocTail *)((char *)p + p->nSize - sizeof(AllocTail)))->nUpLink;
}

static AllocNode* GetLeftNode(HeapInfo* pHeapInfo, AllocNode* p)
{
	return (AllocNode*)(pHeapInfo->pBuf + ((AllocTail *)((char *)p - sizeof(AllocTail)))->nUpLink);
}

HANDLE CreateHeap(int nHeapSize)
{	
	HeapInfo* pHeapInfo;
	pHeapInfo = (HeapInfo*)(new char[sizeof(HeapInfo) + nHeapSize + SHELL_SIZE]);	
	if(pHeapInfo == NULL)
	{
		return NULL;
	}
	pHeapInfo->nHeapSize = nHeapSize + SHELL_SIZE;	
	
	pHeapInfo->nCount = 1;
	pHeapInfo->pHead = (AllocNode *)pHeapInfo->pBuf;
	pHeapInfo->pTail = (AllocNode *)pHeapInfo->pBuf;		

	AllocNode* pNode;
	pNode = pHeapInfo->pHead;	
	
	pNode->nLeftLink = -1;
	pNode->nTag = 0;
	pNode->nSize = pHeapInfo->nHeapSize;
	pNode->nRightLink = -1;

	AllocTail* pTail;
	pTail = FootLoc(pNode);	
	pTail->nUpLink = 0;
	pTail->nTag = 0;

	return pHeapInfo;
}

void DestroyHeap(HANDLE hHeap)
{
	HeapInfo* pHeapInfo;
	pHeapInfo = (HeapInfo *)hHeap;		

	if(pHeapInfo != NULL)
	{
		delete[] (char *)pHeapInfo;
		pHeapInfo = NULL;
	}	
	
	return;
}

static void RemoveHead(HeapInfo* pHeapInfo)
{	
	pHeapInfo->nCount--;		
	
	if(pHeapInfo->pHead->nRightLink == -1)
	{
		pHeapInfo->pHead = NULL;
	}
	else
	{
		pHeapInfo->pHead = (AllocNode *)(pHeapInfo->pBuf + pHeapInfo->pHead->nRightLink);
	}	

	if(pHeapInfo->pHead != NULL)
	{	
		pHeapInfo->pHead->nLeftLink = -1;
		if(pHeapInfo->nCount == 1)
		{
			pHeapInfo->pHead->nRightLink = -1;	
		}
	}
	else
	{			
		pHeapInfo->pTail = NULL;
	}		
	
	return;
}

static void RemoveTail(HeapInfo* pHeapInfo)
{					
	pHeapInfo->nCount--;
	
	if(pHeapInfo->pTail->nLeftLink == -1)
	{
		pHeapInfo->pTail = NULL;
	}
	else
	{
		pHeapInfo->pTail = (AllocNode *)(pHeapInfo->pBuf + pHeapInfo->pTail->nLeftLink);
	}
	
	if(pHeapInfo->pTail != NULL)
	{	
		pHeapInfo->pTail->nRightLink = -1;
		if(pHeapInfo->nCount == 1)
		{
			pHeapInfo->pHead->nLeftLink = -1;
		}
	}
	else
	{			
		pHeapInfo->pHead = NULL;
	}		
	
	return;
}

static void RemoveAt(HeapInfo* pHeapInfo, AllocNode* pNode)
{	
	if(pNode == pHeapInfo->pHead)
	{
		RemoveHead(pHeapInfo);
		return;
	}
	
	if(pNode == pHeapInfo->pTail)
	{
		RemoveTail(pHeapInfo);
		return;
	}	
	
	AllocNode* pPrev;
	AllocNode* pNext;	
	
	if(pNode->nLeftLink == -1)
	{
		pPrev = NULL;
	}
	else
	{
		pPrev = (AllocNode *)(pHeapInfo->pBuf + pNode->nLeftLink);
	}
	
	if(pNode->nRightLink == -1)
	{
		pNext = NULL;
	}
	else
	{
		pNext = (AllocNode *)(pHeapInfo->pBuf + pNode->nRightLink);		
	}	
	
	if(pNext == NULL)
	{
		pPrev->nRightLink = -1;
	}
	else
	{
		if(pPrev != NULL)
		{
			pPrev->nRightLink = GetSelfUplink(pNext);
		}		
	}
	
	if(pPrev == NULL)
	{
		pNext->nLeftLink = -1;
	}
	else
	{
		if(pNext != NULL)
		{
			pNext->nLeftLink = GetSelfUplink(pPrev);
		}		
	}	
	
	pHeapInfo->nCount--;
	
	return;
}

void* AllocMem(HANDLE hHeap, int nSize)
{
	HeapInfo* pHeapInfo;
	pHeapInfo = (HeapInfo *)hHeap;

	if(pHeapInfo->nCount == 0)
	{
		return NULL;
	}

	nSize += SHELL_SIZE;

	AllocNode* p;	
	p = pHeapInfo->pHead;
	while(true)
	{
		if(p->nSize < nSize)
		{	// 不符合条件
			if(p->nRightLink < 0)
			{	// 循环链表构成循环
				return NULL;
			}		
			p = (AllocNode *)(pHeapInfo->pBuf + p->nRightLink);						
		}	
		else
		{	// 满足条件				
			if(p->nSize - nSize <= MINI)
			{	// 把整个空闲块进行整体分配
				AllocTail* pFoot;
				pFoot = FootLoc(p);		// 取尾巴结构
				
				p->nExtraSize = p->nSize - nSize;
				p->nTag = 1;					// 设置头占用标志
				pFoot->nTag = 1;		// 设置尾占用标志					
				
				RemoveAt(pHeapInfo, p);
				return p+1;			
			}
			else
			{
				AllocTail* pOldFreeFoot;
				pOldFreeFoot = FootLoc(p);		// 取尾巴结构

				pOldFreeFoot->nTag = 1;		// 设置占用块尾巴标记(tag):1(占用)				
				p->nSize -= nSize;	// 设置新空闲块头size: 
			
				AllocTail* pNewFreeFoot;
				pNewFreeFoot = FootLoc(p); // 获取新空闲块的foot
				pNewFreeFoot->nTag = 0;		// 设置新空闲块尾巴标记(tag):0(空闲)
				pNewFreeFoot->nUpLink = pOldFreeFoot->nUpLink;	// 设置新空闲块的uplink				

				pOldFreeFoot->nUpLink = pNewFreeFoot->nUpLink + p->nSize;

				AllocNode* pBusyHead;
				pBusyHead = (AllocNode*)((char *)pNewFreeFoot + sizeof(AllocTail));	
				pBusyHead->nExtraSize = 0;
				pBusyHead->nTag = 1;		// p为占用块的头的标记
				pBusyHead->nSize = nSize;	// 	p为占用块的头的的size
				pBusyHead++;
				return pBusyHead;
			}			
		}
	}
}

// 左:忙 右:忙
static void FreeMem1(HeapInfo* pHeapInfo, AllocNode* p)
{
	p->nTag = 0;

	AllocTail* pFoot;
	pFoot = FootLoc(p);	
	pFoot->nTag = 0;

	if(pHeapInfo->nCount == 0)
	{		
		p->nRightLink = -1;
		p->nLeftLink = -1;
		pHeapInfo->pHead = p;
		pHeapInfo->pTail = p;
		pHeapInfo->nCount = 1;
	}
	else
	{			
		pHeapInfo->pTail->nRightLink = GetSelfUplink(p);
		p->nLeftLink = GetSelfUplink(pHeapInfo->pTail);
		p->nRightLink = -1;
		pHeapInfo->pTail = p;
		pHeapInfo->nCount++;			
	}
}

// 左:闲 右:忙
static void FreeMem2(HeapInfo* pHeapInfo, AllocNode* p)
{
	int n;
	n = p->nSize;
	
	AllocNode* pLeftNode;
	pLeftNode = GetLeftNode(pHeapInfo, p);

	int nUplink;
	nUplink = GetSelfUplink(pLeftNode);

	pLeftNode->nSize += n;

	AllocTail* pFoot;
	pFoot = FootLoc(p);
	pFoot->nUpLink = nUplink;
	pFoot->nTag = 0;	

	return;
}

// 左:忙 右:闲
static void FreeMem3(HeapInfo* pHeapInfo, AllocNode* p)
{
	AllocNode* pRightNode;		// 右邻空闲区的头
	pRightNode = (AllocNode *)((char *)p + p->nSize);	// 获取右邻空闲区的头
	p->nTag = 0;			// p为合并后的节点头部

	int nUpLink;
	nUpLink = GetSelfUplink(p);

	int nRightFreeSize;
	nRightFreeSize = pRightNode->nSize;

	RemoveAt(pHeapInfo, pRightNode);	

	p->nSize += nRightFreeSize;	
	FootLoc(p)->nUpLink = nUpLink;
	///增加一个空闲块//
	if(pHeapInfo->nCount == 0)
	{		
		p->nRightLink = -1;
		p->nLeftLink = -1;
		pHeapInfo->pHead = p;
		pHeapInfo->pTail = p;
		pHeapInfo->nCount = 1;
	}
	else
	{	
		pHeapInfo->pTail->nRightLink = GetSelfUplink(p);
		p->nLeftLink = GetSelfUplink(pHeapInfo->pTail);
		p->nRightLink = -1;
		pHeapInfo->pTail = p;
		pHeapInfo->nCount++;		
	}
	//
	return;
}

// 左:闲 右:闲
static void FreeMem4(HeapInfo* pHeapInfo, AllocNode* p)
{
	int n;
	n = p->nSize;
	
	AllocNode* pLeftNode;			// 左空闲节点
	pLeftNode = GetLeftNode(pHeapInfo, p);	

	int nUpLink;
	nUpLink = GetSelfUplink(pLeftNode);

	AllocNode* pRightNode;			// 右空闲节点
	pRightNode = (AllocNode *)((char *)p + p->nSize);

	RemoveAt(pHeapInfo, pRightNode);

	pLeftNode->nSize += n + pRightNode->nSize;	
	
	FootLoc(pLeftNode)->nUpLink = nUpLink;	

	return;
}

void FreeMem(HANDLE hHeap, void* pAddr)
{
	HeapInfo* pHeapInfo;
	pHeapInfo = (HeapInfo*)hHeap;

	AllocNode* p;
	p = (AllocNode *)pAddr;
	p--;

	if((char *)p == pHeapInfo->pBuf)
	{	// 释放地址为堆的头		
		if(pHeapInfo->nCount == 0)
		{	// 没有空闲
			FreeMem1(pHeapInfo, p);
			return ;
		}		

		AllocNode* pRightHead;		// 右邻空闲区的头
		pRightHead = (AllocNode *)((char *)p + p->nSize);	// 获取右邻空闲区的头

		int nRightTag;	
		nRightTag = pRightHead->nTag;

		int nLeftTag;	
		nLeftTag = 1;

		if(nRightTag == 1)
		{	// 右忙
			FreeMem1(pHeapInfo, p);
			return ;
		}
		else
		{	// 右闲
			FreeMem3(pHeapInfo, p);
			return ;
		}
	}

	char* pTail;
	pTail = (char *)p + p->nSize;
	if(pTail == pHeapInfo->pBuf + pHeapInfo->nHeapSize)
	{		
		if(pHeapInfo->nCount == 0)
		{	// 没有空闲
			FreeMem1(pHeapInfo, p);
			return ;
		}		

		int nLeftTag;	
		nLeftTag = ((AllocTail *)((char*)p-sizeof(AllocTail)))->nTag;

		int nRightTag;	
		nRightTag = 1;
		if(nLeftTag == 1)
		{	// 左忙
			FreeMem1(pHeapInfo, p);
			return ;
		}
		else
		{	// 左闲
			FreeMem2(pHeapInfo, p);
			return ;
		}		
	}

	int nLeftTag;	
	nLeftTag = ((AllocTail *)((char*)p-sizeof(AllocTail)))->nTag;

	AllocNode* pRightHead;		// 右邻空闲区的头
	pRightHead = (AllocNode *)((char *)p + p->nSize);	// 获取右邻空闲区的头

	int nRightTag;	
	nRightTag = pRightHead->nTag;

	if (nLeftTag == 1 && nRightTag == 1)
	{
		FreeMem1(pHeapInfo, p);
		return ;
	}

	if (nLeftTag == 0 && nRightTag == 1)
	{
		FreeMem2(pHeapInfo, p);
		return ;
	}

	if (nLeftTag == 1 && nRightTag == 0)
	{
		FreeMem3(pHeapInfo, p);
		return ;
	}

	if (nLeftTag == 0 && nRightTag == 0)
	{
		FreeMem4(pHeapInfo, p);
		return ;
	}

	printf("error");

	return ;
}


int GetAddrSize(void* pAddr)
{
	AllocNode* p;
	p = (AllocNode *)pAddr;
	p--;
	return (p->nSize - sizeof(AllocNode) - sizeof(AllocTail) - p->nExtraSize);
}

void FreeAllMem(HANDLE hHeap)
{
	HeapInfo* pHeapInfo;
	pHeapInfo = (HeapInfo *)hHeap;	
	
	pHeapInfo->nCount = 1;
	pHeapInfo->pHead = (AllocNode *)pHeapInfo->pBuf;
	pHeapInfo->pTail = (AllocNode *)pHeapInfo->pBuf;		
	
	AllocNode* pNode;
	pNode = pHeapInfo->pHead;	
	
	pNode->nLeftLink = -1;
	pNode->nTag = 0;
	pNode->nSize = pHeapInfo->nHeapSize;
	pNode->nRightLink = -1;
	
	AllocTail* pTail;
	pTail = FootLoc(pNode);	
	pTail->nUpLink = 0;
	pTail->nTag = 0;
	return;
}

 

6.  数组接口函数使用说明

6.1 CreateHeap()

 

1、功能说明

此函数用来生成一个内存堆数据结构,执行成功后返回一个句柄,之后分配和释放内存的操作都引用此句柄。

 

2、函数原型

HANDLE CreateHeap(int nHeapSize);

 

3、参数说明

  1. int nHeapSize

    输入参数。堆空间的大小, 单位字节, nHeapSize必须大于0。

 

4、返回值

执行成功返回非NULL的句柄,执行失败时返回NULL。

 

5、相关函数

   DestroyHeap(HANDLE hHeap)

 

 

6.2 DestroyHeap ()

1、功能说明

此函数用来释放指定的堆数据结构以及占用的内存。

 

2、函数原型

void DestroyHeap(HANDLE hHeap);

 

3、参数说明

   1)HANDLE hHeap

      输入参数,hHeap是执行CreateHeap函数返回的句柄。

 

4、返回值

    无。

 

5、相关函数

   CreateHugeArray()

 

6.3 AllocMem()

1、功能说明

此函数用来根据数组索引下标获指定取数组元素地址。

 

2、函数原型

Void* AllocHeap(HANDLE hHeap, int nSize);

 

3、参数说明

   1)HANDLE hHeap

      输入参数,hHeap是执行CreateHeap函数返回的句柄。

 

2)int nSize

      输入参数,申请内存的大小,单位:字节。

 

4、返回值

    地址指针

 

5、相关函数

   FreeMem()

 

6.4 FreeMem()

1、功能说明

此函数用来根据数组索引下标获指定取数组元素地址。

 

2、函数原型

Void FreeMem(HANDLE hHeap,void* pAddr);

 

3、参数说明

   1)HANDLE hHeap

      输入参数,hHeap是执行CreateHeap函数返回的句柄。

 

2)void* pAddr

      输入参数,要释放内存的地址,这个地址必须是之前通过AllocMem函数返回的

     地址。

 

4、返回值

    无

 

5、相关函数

   AllocMem()

 

7. demo

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "MemAlloc.h"

int main(int argc, char* argv[])
{
	HANDLE hHeap;
	hHeap = CreateHeap(10*1024*1024);
	
	void* pAddrArray[1024];

	int i;
	for (i = 0; i < 1024; i++)
	{
		pAddrArray[i] = AllocMem(hHeap, 256);
	}

	for (i = 0; i < 1024; i++)
	{
		strcpy(pAddrArray[i], "1234567890");
	}

	for (i = 0; i < 1024; i++)
	{
		printf("%s\r\n", pAddrArray[i]);
	}

	for (i = 0; i < 1024; i++)
	{
		FreeMem(hHeap, pAddrArray[i]);
	}

	DestroyHeap(hHeap);

	return 0;
}

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值