前言
当我们使用C/C++构建我们程序的时候,经常会遇到这类问题:问题难以复现;大压力下运行几天才能出现;大并发问题下,出现问题现场无法分析定位问题。经过大量的分析总结,发现这类难以解决的问题的原因大量集中在内存越界、内存重复释放等内存问题。
这类问题大致由于分配给一个对象的内存,可能被其他程序重写,或者是由于某些计算错误,用了不属于你的内存。更崩溃的是如果它带有一定的随机性重现,当错误发生的时候,系统没有检测到异常,而是在以一定概率被其他程序重写或复用,问题发生了,这时候问题发生的地方与真正出问题的地方相隔很远。内存方面的问题是出了名的难题,而且一旦发生,影响巨大,甚至触发安全问题。
现有的DPDK已经有内存管理的机制,是通过检测可用内存前后区域是否被修改来判断是否越界,但是现有的DPDK实现只有在rte_free的时候才做内存检测,甚至发生内存问题的时候, 非常少且有效的调试信息输出来帮助定位问题,如果问题带有一定的随机性且很难重现,让人很崩溃。这时候会迫切地需要一种工具来帮助定位调试问题,网上有很多内存管理的工具,五花八门,但是没有一个可用并且好用的工具可以在DPDK中直接使用。
内存检测机制
大多数的内存检测工具采用以下步骤进行检测,比如通过在被保护的堆,栈、全局变量周围建立标记为中毒状态的红区(redzones),如图1所示,在绿色区域表示可访问的进程内存,红色区域表示在它周边插入的红区。
检测工具会检测进程中的所有位置,通过影子内存的状态值来存储真实内存中的每个字节的访问是否安全,这样的影子内存需要一大块连续的虚拟地址空间,如图1所示蓝色的影子区域(shadow region),在程序初始化的时候申请好这片空间。当然了查找影子内存需要非常快才行,一般会构建查找表(lookup table)来记录快速查找每块区域的访问权限。这个查找表并未真正分配,而是在进程启动的时候保存,在需要的时候访问。编译的时候,在每一次内存访问前编译器会帮我们采用代码插桩技术来针对应用程序的每次load和store对影子内存进行检查,它会影响每一次内存访问,并在代码前缀加