• 2006-08-01

    内存之战

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://www.blogbus.com/dreamhead-logs/2957156.html

    Java相对于C/C++的最大进步在于内存管理上,因为手工管理内存太容易出错。谈到内存的问题,首当其冲的应该是申请而未释放造成的内存泄漏,其次是释放而仍使用的野指针,还有多个指针指向同一块内存造成的别名问题,这些都是内存的“标准问题”,任何想批驳C/C++的文章都可以把它们请出来证明C/C++是如此不堪。或许是自己编写的C/C++程序还不够多的原因,对这些指针问题,我始终没有给予足够的重视,不是我从不犯这些错误,而是我觉得通过好的编程习惯可以大幅度降低出现这种错误的几率,更重要的是,即便出现了这种错误,一般都是很容易找出来的。

    照我这么理解,内存岂不是很容易搞定?当然不是。首先,好的编程习惯和调试经验可不是一天两天就能锻炼出来的,需要在项目中不断打磨。更关键的是,内存还有其它的问题。这几天困扰的我便是一个内存的问题。

    现在的工作就是给测试一个尚在开发中的库,库的测试当然就是编写各种各样的程序,既要测试库代码中的bug,也要对接口的合理性进行验证,因为库尚在开发之中,有问题就是在所难免。于是,我被绊了个跟头。

    费了好大劲编写的程序刚一开始运行便崩溃了,对于一个新鲜出炉的程序,我当然知道不能对它寄以特别大的期望,但对出于对自己的信任,我相信自己应该很快让一切步入正轨。但随着崩溃信息走入程序之中,我发现了一个变量出现在一个极低的地址,十六进制的10以内,经验告诉我这个地址是错误的,在我调试用的windows环境中,变量一般不会放到这么低的地址中。于是只好一次次的运行,倒着追踪这个变量内存地址的变化,事实证明,这个变量在之前的运行是正确的,运行到一个库的函数中突然变化了。让我感到一丝安慰的是,我拥有这个库的源代码,不至于让我进入二进制的调试。为了减少代码量,库中大量的使用宏的技巧,这个函数也是。对于编写代码的人来说,宏可以带来优雅,对于调试的人来说,宏简直就是一场恶梦。为了让自己舒服一点,我决定拆了它,于是根据代换规则,把它重新实现出来。

    进入到这个函数之后,首先是分配一个空间,让后就是一个循环赋值的操作。实在看不出有什么异常,只好单步跟踪,眼睛盯着那个变量地址的变化。在循环到一定程度,突然变量的地址变了。我首先想到的是不可能,因为这个函数中根本没有操作过那个变量,但无情的事实摆在面前,让我不得不折服。冷静下来的观察让我发现了问题所在,内存地址的一致,演出了一场声东击西,典型的别名问题。内存地址怎么会一致呢?问题定位到了那个内存分配函数上。

    这个库的底层需要支持垃圾回收,于是,库的开发者重新编写了一套内存管理算法,而这里用到的内存分配,恰恰来自这套自己编写的内存管理函数。一鼓作气追到内存管理函数中去,结果让我大失所望,因为实在从这段内存分配的代码上,我实在看不出有任何的纰漏,只是运行结果告诉我,内存地址有问题。

    接下来的几天,我几次尝试攻克这个问题,一直未果,所能怀疑的只是哪里出错导致内存越界,我程序的验证也因此一拖再拖。当然,我也把这个问题报告给了库的开发者,但始终没能等到满意的答复。

    今天晚上,心血来潮,准备再次进攻。我相信问题出在内存管理的实现上,因为一般内存管理的经典算法本身应该没有任何问题。我在所有内存分配的地方加上了打印语句,然后一点点对内存,终于发现了找到了一个和出问题那段代码有关的内存,其地址与我那个变量地址比较接近。但很快我又否定了自己的想法,因为每次分配都有固定的大小,而把这个地址和大小相加,根本不会越界。至于其它的地方,与那个地址相差甚远,出错的可能性不大。经过一番斗争,我又回到了那个让我怀疑的地址上,我决定跟进去。内存分配没有任何问题,容量是申请的空间减去用作记录的部分也没有问题,再往下走,在处理内存对齐的时候,存放的容量变量突然变了,变得很大。我的心里一阵难以抑制的狂喜,应该就是这里了。经过推算,问题就在这里,因为用错了运算符号,所以,倒置容量这个字段变得很大,因为容量标识的是这段内存的界限,一旦它变大,就会有内存访问越界的情况出现。

    找到问题,一切就变得简单了,剩下的就是修改运行的工作了。

    我想说的内存问题就是这样了,这种问题之所以不好调试,主要的原因是因为出错的地方和把错误表现出来的地方根本不在一起,很难把二者联系起来,这给发现问题带来了很大的难度。

    分享到:

    历史上的今天:

    Moco 0.8.1发布 2013-08-01
    引用地址:

    评论

  • 希望下次这样的好文章可以配上图片。。期待
    回复killvin说:
    多谢提醒,确实在我的blog中,图太少了。
    2006-08-12 14:40:17