Magic Number 在编程中的使用

本文介绍了一种名为MAGIC_NO的技巧,用于调试无锁线程池中的内存管理问题。通过在每个内存块头部设置特定的magic number,可以有效检测指针偏移错误,确保内存管理的正确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MAGIC_NO,好方法!

调试无锁线程池代码过程中,采用了一种很有意思的技术,和大家share一下。她的名字叫:MAGIC NUMBER。

假设我们有了一大块缓冲区(以下称buffer),say,1M,这一块缓冲区将用来满足很多小的顺序到来的内存请求,并且,其释放先后次序和申请次序一致。我们可以考虑采用环形队列来解决这个问题。为了记录分配出去的内存块(以下称buflet)的大小、状态等信息,需要对内存区进行管理,采用如下策略:
(1)每一小块内存头部划分出一小片来记录这块内存的大小、状态,剩余部分供给用户使用。
(2)对于新的请求,首先查看当前空闲池是否能够满足需求,如果不能满足,就往前查看,合并可回收的内存区到空闲池(适用于回环了一周的内存使用状况,首次分配不存在该问题),然后进行分配。分配时,新区域可能比用户需要的区域大,此时需要执行split操作,仅仅将用户需要的内存切割出去,剩余的放入空闲池。
(3) 用户归还内存时将内存块标记为free
如下图所示:


为了实现上述管理,我们需要编写较为复杂的代码(以上是简化模型,实际应用中有更复杂的需求),这里面有个很麻烦的问题就是:指针偏移!为了通过当前块计算出下一个块的首地址,通过 next_addr = current_addr + current_size计算即可,在复杂应用中,情况往往比较复杂,计算可能出错,此时得到的next_addr是个错误的值,用这个错误的next_addr去得到下一块的大小,显然也是错的,就这样,一步算错了,将一路错下去,无日无夜……
如何及时发现这种错误?不要说仔细地写代码,因为,在程序员心中,有个概念必须牢记:软件错误是无法避免的。在一块内存区上,任意位置都可以是一个buflet的起始,当我们得到一个错误的指针时,它表面上看也可以是一个buflet地址,实际上确实错误的。这个错误无法直接检测!这个问题麻烦了我三四个小时后,终于不堪忍受了,想出使用MAGIC_NO的方法:每生成一个buflet的时候,在其头结构中加入一个magic number。每次通过现有指针计算分配一个buflet时,我们就检查magic number域,如果magic number等于某个确定值MAGIC_NO,则表明指针偏移正确,否则报错,让我们知道指针又错了,反过来及时修改代码。

  1. #defineMAGIC_NO0x4D544C/**<asciiforLTM*/
  2. typedefstruct_dfs_api_res_pkt_t
  3. {
  4. intmagic_no;//MagicNumber,0x4D544C
  5. buflet_statestate;//缓冲区状态:RECEIVED,
  6. int16mark;//标记这个packet是否是有效packet
  7. int16block_no;//所属快号
  8. u_int32size;//packet大小,包括本结构和后面的缓冲区
  9. charbuf[];//存储UDP包的缓冲区
  10. }
  11. dfs_api_res_pkt_t;
  12. 1#include<stdio.h>
  13. 2
  14. 3#defineMAGIC_NO0x4D544C/**<someascii,^.^*/
  15. 4unionm{
  16. 5inti;
  17. 6charbuf[4];
  18. 7}x;
  19. 8intmain()
  20. 9
  21. 10{
  22. 11inti=MAGIC_NO;
  23. 12x.i=i;
  24. 13//Iwillshowyouthemagic!
  25. 14printf("%s/n",x.buf);
  26. 15return0;
  27. 16}
  28. ~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值