San Domingo's Blog

Courage, Duty, Honor!

[Java]不同Jar包中出现同名class引起的程序Bug

| Comments

最近在研究boilerplate这个页面自动抽取方法,结果遇到了Stack Overflow的问题,报错现实问题在org.cyberneko.html.HTMLTagBalancer.endElement这里。这个问题是偶尔出现,而且频率也不高,追踪了几天,也找不到问题究竟出在哪里。周末有空了,想想还是来认真fix一下这个bug吧。

吸取了之前没有逻辑性的bug追踪过程,这次算是比较有条理的在解决问题,记录下解决思路,希望自己以后不要在栽在这样的坑里了。

发现问题

我们的java应用都是用shell脚本启动,在服务器上运行时,报出Stack Overflow的错误。接到报错后,立刻开始调试程序,在本地计算机上用shell脚本启动,也报同样的错误,然后在IDE中调试,一切正常。

解决思路

  1. google了下这个问题,发现cyberneko官方有issue,承认这是个bug,并在新版本中已经修复。
  2. 检查shell脚本,确认传入到Java程序中的参数时正确的。
  3. 查看并对比了IDE和shell脚本启动Java程序的jvm参数。发现略有不一样,逐个对比调试发现在shell脚本中使用IDE配置的classpath运行程序竟然没有报错,这下问题定位到错在classpath上了。
  4. 将shell和IDE中的classpah拿出来对比,发现cyberneko的版本一致,已经是最新的了。
  5. 栽入坑中若干小时…尝试对两个classpath配置逐条对比,并在正确的classpath上逐条来测试,企图重现错误。
  6. 许久才联想想到classload加载类的机制,才想到classpath中条目顺序的问题,试了一下,发现cyberneko和boilerpipe这两个jar包顺序如果颠倒了,就会报错。
  7. 检查boilerpipe和cyberneko这两个jar包,发现问题根源

    boilerpipe中竟然copy了cyberneko的两个类的代码,而且包名也没有修改,查看源码后,boilerpipe里copy的代码应该是比较旧版本的,因而导致了报错。

  8. 最后便是修复bug,我采取了比较简单的而暴力的方式,将boilerpipe的jar包中copy的代码直接删除,因为我的classpath中有cyberneko的jar包,所以在回归测试时,boilerpipe的抽取算法依然可用,至此,bug修复完毕。

事后

Bug追踪还是得顺藤摸瓜!切忌无脑失错。对于像我这种记性不好的,最好在纸张上记录下整个Bug追踪的线路,这样哪些路已经走过,哪些路走不通,哪些路还可以尝试,一目了然。

Java, Pit

« Mac新手指南(编写中) zsh新手指南 »

Comments