易码技术论坛

 找回密码
 加入易码
搜索
查看: 45853|回复: 10

[演示] 问问gameghost的malloc的问题

[复制链接]
发表于 2007-11-17 21:41:25 | 显示全部楼层 |阅读模式
我正在写一个软件,其中要用很多动态内存分配,但现在我遇到了无法解决的问题.
看一段代码:

  1. void main()
  2. {
  3. settop(0x6fff);
  4. int a,b,c,d;
  5. malloc(4,&a);
  6. malloc(1,&b);
  7. malloc(2,&c);
  8. free(b);
  9. malloc(1,&d);
  10. printf("%d\n",d);
  11. getchar();
  12. }
复制代码

运行结果是0.这是怎么回事?
还有,最好再说说用这个malloc.y的时候要注意些什么,我是很不了解LAVA程序运行时是怎么用内存的,所以用起它来没什么把握.或者简单说说LAVA程序怎样使用内存吧.谢谢.
 楼主| 发表于 2007-11-18 11:42:04 | 显示全部楼层
啊,我忽然知道了为什么malloc的原型是int malloc(int,int&)而不是int malloc(int),原来这是为了arrange,arrange函数会把曾被当作第二个参数传进来的所有地址里的int内容改掉,因为若有已被释放的内存块夹在尚在使用的内存块当中时,会造成所有已分配的内存块内容的移动.所以arrange函数需要为所有"接受过服务"的int变量(里面放的是地址)负责.由此我也懂得了为什么gameghost说这种从非底层实现的malloc限制了指针的灵活性.
那么我觉得在程序里尽量不要用arrange,除非在十分有把握的情况下(不要让arrange函数操作悬虚的地址).
我在顶楼贴出的程序的问题是可以用arrange解决的(free(b)后立即arrange),但是就算不arrange内存,malloc也不应往&d中放零,这是bug吧?
发表于 2007-11-23 19:19:49 | 显示全部楼层
那个模块我也没用过,代码怎么改的我也不很清楚......

下面这个代码是所有解释器通用的,包括gvm,gvm2,lavax.
而且已经去掉了整理内存,也不需要记录指针的地址,但是在释放时会检测合并空闲的内存,提高内存的利用率.
  1. #define RamSize 0x6FFF      //解释器能使用的最大内存地址(0x6fff(LavaX20K), 0x7fff(LavaX24K), 0xffff(GVM2))

  2. long RamMax = RamSize;
  3. long ListHead = RamSize;
  4. long ListEnd = RamSize;

  5. struct INFO
  6. {
  7.        long next;                //下一块内存地址
  8.         long last;                //上一块内存地址
  9.         long pointadd;        //被返回指针的地址
  10.         long size;                //大小
  11.         char used;                //是否空闲
  12. };

  13. #define INFO_next_offset 0
  14. #define INFO_last_offset 4
  15. #define INFO_pointadd_offset 8
  16. #define INFO_size_offset 12
  17. #define INFO_used_offset 16

  18. long GetRamSize(long point)                //取得内存块的大小
  19. {
  20.         long Number;
  21.         memcpy(&Number, point - sizeof(struct INFO) + INFO_size_offset, 4);
  22.         //return ((INFO *)point)->size;
  23.         return Number;
  24. }
  25. /*
  26. void ShowRamState(long x, long y)        //显示当前动态内存状态
  27. {
  28.         long info;
  29.         if (ListHead == RamMax)
  30.         {
  31.                 return;
  32.         }
  33.         for (info = ListHead; info != NULL; )
  34.         {
  35.                 DigitOut(x, y, info + sizeof(struct INFO));
  36.                 DigitOut(x + 50, y, GetRamSize(info + sizeof(struct INFO)));
  37.                 if (*(info + INFO_used_offset))
  38.                 {
  39.                         TextOut(x + 90, y, "使用中");
  40.                 }
  41.                 else
  42.                 {
  43.                         TextOut(x + 90, y, "空闲");
  44.                 }
  45.                 y = y + 16;
  46.                 memcpy(&info, info + INFO_next_offset, 4);        //info = info->next;
  47.         }
  48.         TextOut(x, y, "RamEnd");
  49. }
  50. */
  51. void ClearRam()        //重置动态内存
  52. {
  53.         RamMax = RamSize;
  54.         ListHead = RamSize;
  55.         ListEnd = RamSize;
  56. }

  57. void free(long point)        //释放内存,并合并其前后的空闲内存
  58. {
  59.         long info;
  60.         long size1,size2;
  61.         long last, next;
  62.         info = point - sizeof(struct INFO);
  63.         memcpy(&last, info + INFO_last_offset, 4);        //last = info->last;
  64.         memcpy(&next, info + INFO_next_offset, 4);        //next = info->next;
  65.         if(next == 0)//判断是否为最后一块内存
  66.         {
  67.                 //查找最后一个非空闲内存块
  68.                 while (!(*(last + INFO_used_offset)))
  69.                 {
  70.                         memcpy(&last, last + INFO_last_offset, 4);        //last = last->last;
  71.                 }
  72.                 ListEnd = last;
  73.                 memset(ListEnd + INFO_next_offset, 0, 4);//重置链表尾
  74.         }
  75.         else
  76.         {
  77.                 //向上检测合并
  78.                 if (info != ListHead)
  79.                 {
  80.                         if (!(*(last + INFO_used_offset)))
  81.                         {
  82.                                 memcpy(&size1, last + INFO_size_offset, 4);        //size1 = last->size;
  83.                                 memcpy(&size2, info + INFO_size_offset, 4);        //size2 = info->size;
  84.                                 size1 = size1 + size2 + sizeof(struct INFO);//
  85.                                 memcpy(info + INFO_size_offset, &size1, 4);        //last->size = size1 + size2 + sizeof(struct INFO);
  86.                                 memcpy(info + INFO_last_offset, last + INFO_last_offset, 4);        //info->last = last->last;
  87.                                 if (last == ListHead)
  88.                                 {
  89.                                         ListHead = info;
  90.                                 }
  91.                                 else
  92.                                 {
  93.                                         memcpy(&last, last + INFO_last_offset, 4);
  94.                                         memcpy(last + INFO_next_offset, &info, 4);        //last->last->next = info;
  95.                                 }
  96.                         }
  97.                 }
  98.                
  99.                 //向下检测合并
  100.                 if (!(*(next + INFO_used_offset)))
  101.                 {
  102.                         memcpy(next + INFO_last_offset, info + INFO_last_offset, 4);//next->last = info->last;
  103.                         memcpy(&size1, info + INFO_size_offset, 4);                //
  104.                         memcpy(&size2, next + INFO_size_offset, 4);                //
  105.                         size1 = size1 + size2 + sizeof(struct INFO);        //
  106.                         memcpy(next + INFO_size_offset, &size1, 4);                //info->size = size1 + size2 + sizeof(steuct INFO);
  107.                         if (info == ListHead)
  108.                         {
  109.                                 ListHead = next;
  110.                         }
  111.                         else
  112.                         {
  113.                                 memcpy(&last, info + INFO_last_offset, 4);
  114.                                 memcpy(last + INFO_next_offset, &next, 4);                //info->last->next = next;
  115.                         }
  116.                         info = next;
  117.                 }
  118.                
  119.                 *(info + INFO_used_offset) = 0;
  120.         }
  121. }

  122. long malloc(long R_SIZE)//分配内存,返回被分配的内存地址
  123. {
  124.         long lastadd; //暂存一下地址
  125.         long info;
  126.         long temp;
  127.         long lastornext;
  128.         char test;
  129.         
  130.         //寻找现有空闲内存
  131.         if( ListHead != ListEnd) //说明有已开辟的内存
  132.         {
  133.                 info = ListHead;
  134.                 while(info)
  135.                 {
  136.                         memcpy(&temp, info + INFO_size_offset, 4);
  137.                         if((*(info + INFO_used_offset) == 0) && (temp >= R_SIZE))//未使用的内存块,且容量足够,多出的空间被设置为新的空闲内存
  138.                         {
  139.                                 if(temp - R_SIZE > sizeof(struct INFO))//有足够的多余空间设置新的空闲内存
  140.                                 {
  141.                                         lastadd = info + R_SIZE + sizeof(struct INFO);//添加节点
  142.                                        
  143.                                         if(info != ListHead)
  144.                                         {
  145.                                                 memcpy(&lastornext, info + INFO_last_offset, 4);        //lastornext = info->last;
  146.                                                 memcpy(lastornext + INFO_next_offset, lastadd, 4);        //lastornext->next = lastadd;
  147.                                         }
  148.                                         else
  149.                                         {
  150.                                                 ListHead = lastadd;
  151.                                         }
  152.                                        
  153.                                         lastornext = lastadd;
  154.                                         memcpy(lastornext + INFO_next_offset, &info, 4);        //lastornext->next = info;
  155.                                         memcpy(lastornext + INFO_last_offset, info + INFO_last_offset, 4);        //lastornext->last = info->last;
  156.                                         memcpy(&temp, info + INFO_size_offset, 4);
  157.                                         temp = temp - R_SIZE - sizeof(struct INFO);
  158.                                         memcpy(lastornext + INFO_size_offset, &temp, 4);        //lastornext->size = info->size - R_SIZE - sizeof(struct INFO);
  159.                                         *(lastornext + INFO_used_offset) = 0;                                //lastornext->used = 255;
  160.                                         memcpy(info + INFO_last_offset, &lastornext, 4);        //info=>last = lastornext;
  161.                                         memcpy(info + INFO_size_offset, &R_SIZE, 4);                //info->size = R_SIZE;
  162.                                 }
  163.                                 *(info + INFO_used_offset) = 255;
  164.                                 return (info + sizeof(struct INFO));
  165.                         }
  166.                         memcpy(&info, info + INFO_next_offset, 4);
  167.                 }
  168.         }
  169.         
  170.         //开辟新内存
  171.         if(&test + R_SIZE + sizeof(struct INFO) >= ListEnd)
  172.         {
  173.                 return 0;
  174.         }
  175.         
  176.         //保留上一个内存块的地址
  177.         lastadd = ListEnd;
  178.         
  179.         if(ListEnd < RamMax)
  180.         {
  181.                 //修改上一个内存块的next地址
  182.                 temp = ListEnd - R_SIZE - sizeof(struct INFO);
  183.                 memcpy(ListEnd + INFO_next_offset, &temp, 4);        //ListEnd->next = ListEnd - R_SIZE - sizeof(struct INFO);
  184.                 //修改动态内存链表尾
  185.                 ListEnd = temp;
  186.         }
  187.         else
  188.         {
  189.                 //第一块内存
  190.                 ListEnd = ListEnd - R_SIZE - sizeof(struct INFO);
  191.                 ListHead = ListEnd;
  192.         }
  193.         
  194.         info = ListEnd;
  195.         memcpy(info + INFO_last_offset, &lastadd, 4);        //info->last = lastadd;
  196.         memset(info + INFO_next_offset, 0, 4);                        //info->next = 0;
  197.         memcpy(info + INFO_size_offset, &R_SIZE, 4);        //info->size = R_SIZE;
  198.         *(info + INFO_used_offset) = 255;                                //info->used = 255;

  199.         return info + sizeof(struct INFO);
  200. }
复制代码
 楼主| 发表于 2007-11-24 13:20:55 | 显示全部楼层
我自己也写了一个动态内存分配的Y,不久也发到论坛.
发表于 2007-11-25 19:38:25 | 显示全部楼层
内存控制块结构稍嫌笨重,浪费空间,其实8字节足以
程序代码也过繁复,几十行足以
发表于 2007-11-26 11:31:44 | 显示全部楼层
在不支持指针和引用环境下使用64K内存,不知该如何化简代码......
内存信息结构的确可以化简(7字节).(而且上面程序中的"pointadd"成员可以去掉).
关于代码的化简,Lee大叔请赐教......
发表于 2007-11-28 14:16:21 | 显示全部楼层
内存块头只需要4字节的size(如只支持64k可节省为2字节)+1~4字节的块信息(至少一个使用位表达内存是否已占用)
所以内存块头最多8字节,最少3字节

把内存组织成一个链表,每个内存块有一个块头+n字节的内存(供用户使用),这样就可以了,分配释放很简练
发表于 2007-11-28 15:41:54 | 显示全部楼层
嗯,但是如果要组成链表,没有前后内存块的指针会对内存操作造成困难,所以我还是改成7字节好了~
发表于 2007-11-28 16:08:33 | 显示全部楼层
不对。只有有字节数就可以。
单向链表足以。
否则,分配1字节就白白浪费了4字节(7-3=4)
 楼主| 发表于 2007-11-30 19:39:42 | 显示全部楼层
看看我的DMA(Dynamic memory allocation),怎样?
这个DMA和gameghost的有一些不一样,它是让用户来指定一块内存作为DMA.
  1. struct DMANode
  2. {
  3. int size;
  4. int prev;
  5. int next;
  6. };

  7. int mstart,msize;
  8. int nhead;

  9. void initDMA(int start,int size)
  10. {
  11. mstart=start;
  12. msize=size;
  13. nhead=NULL;
  14. }

  15. int malloc(int size)
  16. {
  17. struct DMANode& nq,vac,np;
  18. &nq=NULL;&vac=mstart;&np=nhead;
  19. while(&np){
  20.   if(&vac+size+sizeof(DMANode)<=&np)
  21.    break;
  22.   &nq=&np;
  23.   &vac=&np+np.size+sizeof(DMANode);
  24.   &np=np.next;
  25. }
  26. if(!&np){
  27.   if(&vac+size+sizeof(DMANode)>mstart+msize)
  28.    return 0;
  29. }
  30. vac.size=size;
  31. vac.prev=&nq;
  32. vac.next=&np;
  33. if(&nq)nq.next=&vac;
  34. else nhead=&vac;
  35. if(&np)np.prev=&vac;
  36. return &vac+sizeof(DMANode);
  37. }

  38. void free(int pointer)
  39. {
  40. struct DMANode& ncur,npre,npost;
  41. &ncur=pointer-sizeof(DMANode);
  42. if(ncur.prev){
  43.   &npre=ncur.prev;
  44.   npre.next=ncur.next;
  45. }else nhead=ncur.next;
  46. if(ncur.next){
  47.   &npost=ncur.next;
  48.   npost.prev=ncur.prev;
  49. }
  50. }

  51. void main()
  52. {
  53. }
复制代码
是不是小巧?
发表于 2007-12-1 09:42:08 | 显示全部楼层
唉,看了LS的代码才发现以前的代码是多么的*^$#&@......

所以,我重写了一次,代码如下,gvm1和LavaX用的,内存块的信息只占两字节.
下面的代码内存的使用依然是从可用内存的最大位置开始分配,因为这样可以让内存的使用更有弹性.
  1. /******************************************
  2.   malloc.c - 动态内存分配
  3.   gameghost  2007/11/30
  4. ******************************************/
  5. int _pMMax = 0x7000;//最大安全地址(20K:0x7000, 24k:0x7FFF)
  6. int _pMHead = 0x7000;
  7. /*struct _MemoryInfo{
  8.     bool bUsed : 1;
  9.     short nSize : 31;
  10. };*/

  11. int malloc(int _NewSize)
  12. {
  13.     int _nSize;
  14.     int &_rMInfo;
  15.     int &_rMInfoNext;
  16.     &_rMInfo = _pMHead;
  17.    
  18.     while (&_rMInfo < _pMMax){
  19.         if (_rMInfo > 0){
  20.             goto L_CombineLoopStart;
  21.             while (_rMInfoNext > 0 && &_rMInfoNext < _pMMax){
  22.                 _rMInfo = _rMInfo + _rMInfoNext + sizeof(int);
  23. L_CombineLoopStart:        &_rMInfoNext = &_rMInfo + _rMInfo + sizeof(int);
  24.             }
  25.             
  26.             if (_rMInfo >= _NewSize){
  27.                 if (_rMInfo > _NewSize){
  28.                     &_rMInfoNext = &_rMInfo + (_nSize = _NewSize + sizeof(int));
  29.                     _rMInfoNext = _rMInfo - _nSize;
  30.                     _rMInfo = _NewSize;
  31.                 }
  32.                 _rMInfo = _rMInfo | 0x8000;
  33.                 return &_rMInfo + sizeof(int);
  34.             }
  35.         }
  36.         &_rMInfo = &_rMInfo + (_rMInfo & 0x7FFF) + sizeof(int);
  37.     }
  38.     if (_pMHead)
  39.         &_rMInfo = _pMHead;
  40.     else
  41.         &_rMInfo = _pMMax;
  42.     if (&_NewSize + 16 > &_rMInfo - _NewSize)
  43.         return 0;
  44.     &_rMInfo = (_pMHead = &_rMInfo - _NewSize - sizeof(int));
  45.     _rMInfo = 0x8000 | _NewSize;
  46.     return &_rMInfo + sizeof(int);
  47. }

  48. void free(int &_rMInfo)
  49. {
  50.     if (&_rMInfo == _pMHead)
  51.             _pMHead = &_rMInfo + _rMInfo + sizeof(int);
  52.     else{
  53.             &_rMInfo = &_rMInfo - 2;
  54.             _rMInfo = _rMInfo & 0x7FFF;
  55.     }
  56. }
复制代码

[ 本帖最后由 gameghost 于 2007-12-1 09:47 编辑 ]
您需要登录后才可以回帖 登录 | 加入易码

本版积分规则

Archiver|手机版|小黑屋|EMAX Studio

GMT+8, 2024-3-28 17:22 , Processed in 0.010508 second(s), 18 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

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