步步为营,搞定第一个memory leak

2008年8月18日的不眠夜最终成为了难忘的时刻。看来国人青睐数字8也许真的不是完全没有道理。
 
Memory leak,而且是AddReft和Release带来的memory leak。当你面对286个调用栈的时候,你就能体会到人与神之间的区别。
 
讨论,和XL热烈地讨论。决定写一个工具来帮助我解决当前的问题——不知道前景如何,但似乎感觉到这是唯一的选择。
 
第一次的结果出来,等于白干,没有任何有用的信息。下班时间到了,简单地去了teriyaki。然后赶回我的window office,继续战斗。
 
深刻地体会了一把什么叫做“理论联系实际”。理论知识我认为自己还是充足的,要不他们为什么不hire一博士生呢?这至少说明我的老板们还是觉得我的知识是够用的。花了些时间分析了一下实际的问题。突然,想到了一个关键的数据结构——非常适合当前这个问题的数据结构。于是,理论开始和实际结合。事实证明,后面的路因此而好走了许多。当build出了这个数据结构之后,又如何下手做分析呢?或者说,我用什么办法让我的工具告诉我问题出在哪里呢?各种“想像”中的理论都涌现出来了,但是没见到有什么好的思路。只好反复检验数据结构,看看实际的数据到底有什么特点。终于,放弃对最“完备”的解决方案的追求,改为基于最可能的情况的假设。
 
这次写工具用的是C#,一个可以让你完全集中于具体问题,而不是各种基础数据结构的超级语言。事实上,这是一个前所未有的编码体验。按理说,编码的经验也不少了,但这一次真的是实践了XL不断向我介绍的,从老板那里学来的编码秘籍。用他的话说,叫做“正规军,阵地战”(当我听到“阵地战”这个词的时候,脑子里浮现的是坦克配机枪兵加MM)。所有的编码基于必要的假设,用Assert向所有不满足假设的情况说“No“。这样做的结果,就是我竟然没有调试过我的工具。出现了Assert就意味着输入不规范或者是必要的改动。不是我刻意地不去调试,而是这样的“阵地战”,一下子就知道问题出在哪里,没有调试的必要。
 
当消灭了所有的Assert之后,我的工具向我展示了它的成果:从286个调用栈中,找到了6个可疑的栈。而这6个可疑的栈中,有5个栈顶都是非常基础的函数,没有什么理由会引入memory leak或者说,它们理应如此:因为它们可能就是为了创建或清理对象,从而是memory leak的疑似患者。只剩下最后一个。当时我并没有对这个工具抱多大的信心。但当我查看这最后一个栈的栈顶函数的修改记录时,突然发现有若干Release被去掉。似乎是新加入的代码没有完全清理干净。事实证明,最后的修改非常简单,合理,而且正是在那个栈的栈顶函数里面。
 
如果用一句话来形容当时的感觉,那一定是康托的名言:“Je le vois, mais je ne crois pas.” (I see it but I cannot believe it) 。康托说这话,是因为他证明了一个正方形上的点和它一条边上的点的个数一边多。我说这话,是因为在我还没有完全明白为什么我的工具能有效之前,就已经被它的效果所震撼。
 
今天白天,见到了老板,向他介绍了我的工作。老板果然是技术狂类型。平时的事情他都少有时间多聊,这次则很有兴致地认真听我介绍。他很高兴,特别是这个leak并不在我们组负责的模块里。他也坦言,在一个不熟悉的模块里找memory leak确实是nightmare。也许还有一个原因:这个问题是他的老板引入的。
 
这件事情给我带来了以下的启发:
  • 很多时候,你是不知道你所掌握的知识什么时候可以帮助你。所以对各种知识,要么投资,要么放弃。不可投机。
  • 不要想着“终极”解决方案,至少对工程师是这样的。从最常见的假设,而不是最纯粹的假设出发,你会走得比想像的更远
  • 要“正规军,阵地战”。(机械化?)
  • 要具体问题,具体分析。所谓具体,不是说“这一类问题”,而是说“这一个问题”。了解具体问题的特点,算是知己知彼。解决一个问题,胜过解决不了任何问题。
  • 终于想到了如何证明正方形拥有和它一条边一样多的点。下次blog再写如何证明,有兴趣的朋友谈谈你的想法啊。

The people bowed and prayed to the XML God they made.
                                                                   — tianlynn

此条目发表在计算机与 Internet分类目录。将固定链接加入收藏夹。

步步为营,搞定第一个memory leak》有 1 条评论

发表回复