简述内存管理的原理和其简单实现

我们平时在linux或者其他的嵌入式系统中经常会用到两个函数,malloc和free。因为有这种动态内存分配的方法,所以给我们日常的编程带来了很多的便捷之处。那么,这两个函数其工作机理是怎么样的呢?在这里,我不想太过复杂地去阐述操作系统中其真正的运行过程,只是把这种动态内存分配的一些思路给说明一下,因为真正的动态内存分配是十分复杂的,我这里只能简单地描述其中的一种,并用C来把这种动态内存分配的方法给模拟出来。
malloc就是从一块空间中开辟出有一部分能用的内存块,返回给用户的是这块分配好的空间的首地址。而free正好相反,其作用是把分配好的空间重新归还于原来的地方,就是我们常说的“释放内存”。
相对free而言,malloc还是比较好理解,而free中的释放又是怎么一回事呢?简单的来说,比如我们在一块内存中占用了其间的一块空间,那么此时操作系统中的某个机制就会把这个事件记录下来,给已经分配给用户的这块空间作好标志,防止下次再次分配的时候会涉及到这部分空间,造成指针越界。
而free的实现和其工作机理,要比malloc要复杂的多了。其要做的工作,不仅仅是把分配过的空间的标志位给擦除掉,而且还要把内存中的碎片进行整合,这是非常必要的。内存中的碎片存在的越多,本来可分配的内存会变得越来越少,最后变得不可分割,从而导致malloc失败,导致程序异常中断。
可以用C来对上述的动态内存分配进行模拟实现。思路是,取一块数组,一部分可分配空间,一部分是用于记录当前分配空间状态的目录,通过查询目录来获取此时的内存分配情况,管理可分配空间,从而实现动态分配方法。实现代码如下:

#include<stdio.h>
#include<time.h>
#include<string.h>

#define MEMSIZE 10000   //总内存块的大小
#define CATALOG_COUNT_MAX 100   //目录的个数

char memory[MEMSIZE];
typedef struct mumm
{
   void *start; /*指向当前分配空间的首地址*/
   int used;    /*分配的标志位,1表示已分配,0表示空闲*/
   int size;    /*该目录指向的空间的大小*/
}catalog;

catalog *memu;  //目录指针

void init()
{
/* 定义好一串目录链表,用于查询分配,个数为100个。同时给目录进行初始化 ,其中,第一个目录指向的就是未分配的总内存大小*/
   memu = (catalog *)(memory + MEMSIZE - sizeof(catalog)*CATALOG_COUNT_MAX);
   memu[0].start = memory;
   memu[0].used = 0;
   memu[0].size = MEMSIZE - sizeof(catalog)*CATALOG_COUNT_MAX;

   int i;
   for(i = 1;i < CATALOG_COUNT_MAX; i++)
   {
      memu[i].start = NULL;
      memu[i].used = 0;
      memu[i].size = 0;
   }
}

/* malloc 的实现方法 */
void *mymalloc(int size)
{
   int i,j;
   /*查询所有目录,看是否有空闲的数据块*/
   for(i = 0;i < CATALOG_COUNT_MAX; i++)
   {
       /*找到了一块数据块*/
      if(memu[i].size >= size && memu[i].used == 0)
      {
          /*标记为使用中*/
         memu[i].used = 1;
         for(j = 0;j < CATALOG_COUNT_MAX; j++)
         {
         /*查询目录,寻找未有分配状态的目录*/
            if(memu[j].used == 0 && memu[j].size == 0)
            {
               /*若找到,把该目录指针置于已分配的空间的后面,并分配余下空间大小,并返回*/
               memu[j].start = memu[i].start + size;
               memu[j].size = memu[i].size - size;
               memu[i].size = size;
               return memu[i].start;
            } 
         }
         break;

      }

   }
      return memu[i].start;
}

/*free 的实现方法*/
void *myfree(void *p)
{
   int i, j,  k;
   for(i = 0;i < CATALOG_COUNT_MAX; i++)
   {
       /*从目录中寻找要释放的内存,通过其指向的首地址和使用状态来寻找*/
      if(p == memu[i].start && memu[i].used == 1)
      {
          /*找到了,把标志位清0。但此时工作并未结束,需要整理内存碎片*/
         memu[i].used = 0;
         for(j = 0; j < CATALOG_COUNT_MAX; j++)
         {
             /*寻找目录,找到指向要释放的空间的后一块内存,如果该内存仍在使用中,则放弃合并,如果未使用,此时把后一块空间合并到要释放空间的内存中来,组成一块新的大的内存块*/
            if((memu[i].start + memu[i].size == memu[j].start) && memu[j].used == 0)
            {
               memu[j].start = NULL;            
               memu[i].size = memu[j].size + memu[i].size;
               memu[j].size = 0;
               break;
            }
         }
         for(k = 0;k < CATALOG_COUNT_MAX;k++)
         {
         /*同上,寻找目录,找到指向要释放的空间的前一块内存,如果该内存仍在使用中,则放弃合并,如果未使用,此时把要释放的空间合并到前一块空间的内存中来,组成一块新的大的内存块*/
               if((memu[k].start + memu[k].size == memu[i].start) && memu[k].used == 0 )
               {
                  memu[i].start = NULL;
                  memu[k].size = memu[i].size + memu[k].size;
                  memu[i].size = 0;
                  break;
               }
         }
         break;
      }
   }
}

/* 该主函数为压力测试,如果够完成9999次malloc和free,那么表示该动态分配方法没有问题 */
int main(int argc, char *argv[])
{
   init(); 
   int i;
   char *pp[80];
   int n;
   char ch;
   for(i = 0;i < 80;i++)
      pp[i] = "-1";
   srand(time(NULL));
   for(i = 0;i < 10000;i++)
   {
      printf("i = %d\n",i);
      n = random()%80;
      if(strcmp(pp[n], "-1") == 0)
      {
         pp[n] = (char *)mymalloc(random()%100 + 1);
         if(pp[n] == NULL)
            break;
         strcpy(pp[n], "a");
         printf("malloc %d\t%x\n", n, pp[n]);
      }
      else
      {
         printf("free %d\t%x\n", n, pp[n]);
         myfree(pp[n]);
         pp[n] = "-1";
      }
   }/*
   int *p = mymalloc(50);
   int *a = mymalloc(100);
   int *b = mymalloc(100);
   int *c = mymalloc(100);
   int *d = mymalloc(1000);
   int *f = mymalloc(7450);

   printf("%p\n",p);
   printf("%p\n",a);
   printf("%p\n",b);
   printf("%p\n",c);
   printf("%p\n",d);

   myfree(a);
   myfree(b);

   int *e = mymalloc(150);
   printf("%p\n",e);
   int *g = mymalloc(100);
   printf("%p\n",g);
   int *h = mymalloc(100);
   printf("%p\n",h);
   int *i = mymalloc(100);
   printf("%p\n",i);

*/
   return 0;
}

其结果如下:

i表示malloc和free的次数,如malloc 60 8049339 表示malloc 60byte大小空间地址为0x8049339。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值