定位Bug技巧总结

解决Bug是编程人员的天职(创造Bug算是一种天赋吧),甚至有人这么认为:开发人员的能力可以依据他能决解Bug的复杂程度来评定。简单的Bug大多数程序员是靠臆断来解决的,但是当Bug隐藏在代码的最深处,臆断不能够解决问题的时候,或许我们就得依靠些许技巧而不是重启。

1.打印输出,在关键位置用System.out.print(); 输出即时参数或者结果(事实上我更赞同用System.err.print(); 因为那样你的输出更明显),然后来判断程序的走向是否正确无疑简单快捷粗暴,程序新手也乐此不疲的使用打印来寻找Bug,但是这种方法缺陷是显而易见的:要求程序规模不能太大,因为你很难找到合适的地方,而且往往你也不知道打印出来的参数是什么意思;不适宜多线程环境下使用,你无法确定打印的顺序;要求程序运行最好是简单有序的,而且Bug是毕现的;线上程序出问题无法及时找到问题,必须在本地加上打印进行调试;

2.打印堆栈,通过在事发地点主动调用 new Exception().printStack(); 帮助程序员了解程序的走向。特别是当某个接口被广泛调用的时候:当程序出错,你希望找到错误的源头,那么你就可以通过打印错误堆栈来找到始作俑者。

3.臆断错误信息,通过系统打印的错误堆栈信息来推测错误原因并加以解决。好吧,这里我实在讽刺大多数不精明的程序员(同时也包括我自己)在看到错误信息后,迫不及待的享受解决Bug的快感,并不仔细查看堆栈信息,往往只解决了表面问题而忽略了更深层次问题。因为在这里受过的挫折太多了,我不得不举两个例子来加以警告:
情景i:《修仙》项目初期,玩家在进行某些位移操作时候服务器会报出空指针异常错误,于是我根据错误堆栈信息来到了事发地点,并且加上了判空操作并 以为解决了这个问题,事实上当回过头来仔细检查的时候发现这个错误是由于底层移动组件的报错引起的,也就是说如果没有检查,我仅仅把表面解决了等同于我吧错误隐藏的更深了,看起来表现没有错,但是底层在不停的进行错误的操作,谁也不知道最后会发生什么。
情景ii:项目线上运行时,同事拿给我一份错误的堆栈信息,是一个ConcurrentModificationException,也就意味着我需要仔细检查一下我的迭代器,防止元素的意外添加和移除,我简单的看了下报错的行数,“那里”恰好是一个循环,于是我对这个循环做了仔细的深入的检查,并没有发现错误,于是我决定找同事聊一下,我们一起仔细的看了遍堆栈信息,尴尬的发现我找错地方了 ,由于本地有部分代码没有提交,因此本地的行数和服务日志记录的报错的行数不一致,也就是说我根本没有仔细的查看错误堆栈信息。为了避免类似的尴尬,请各位务必仔细查看错误的堆栈详情。
此处的所谓臆断,其实我想说以前的我并不是这样的,那时候我并不了解各个异常的含义,但是我对它们很感兴趣,我会仔细阅读错误堆栈信息,找到问题所在,并且试图发现更深的问题,但不知道什么时候开始,看到异常堆栈直觉会告诉我这个异常是这么回事,代表着什么什么,一般是由于什么错误操作导致的,然后按照习惯去解决它。虽然根据经验去推测错误本身并没有错,但我想作为程序员,检查错误时的仔细态度是必不可少的。

4.代码调试, 使用调试工具进行代码调试,可以说是很通用万能的查找Bug的手段,可以说是程序员基本功。调试没有什么还说的,只能说代码调试容易上手,但在程序中快速找到合适的地方断点才是难点。断点调试虽然好用,依然有些缺陷:不能用于线上程序;多线程环境会影响到调试的正确性。

5.日志记录,通用的做法就是在程序中增加不同级别的日志记录。日志记录可以说是一种比较全面的寻找和解决Bug方式,根据日志记录的异常堆栈信息找出Bug所在并加以解决是一种理想的状态,当然程序中哪里加日志,按什么格式和形式追加日志(按照不同纬度,不同视角)都决定了你寻找和解决Bug的轻松程度,尤其是在多线程环境中(没错,日志可以用来记录多线程环境下那些不容易复现的Bug)。记录日志很容易,拿Java来说有很多优秀的用来记录日志的框架,如Logger4j,Slf4j等,允许使用者定制日志的格式和形式,但是阅读日志却不是那么容易。通常一个成熟线上产品的日志,每天的日志就可以达到GB级别,每一篇日志可能也是MB的文档,在这些日志中找到你想要的可能需要一些技巧:熟悉程序是很必要的,起码知道异常模块的入口和出口;放弃使用鼠标,阅读日志时用鼠标滑来滑去绝对不是理智的做法,你应该使用查找来帮助你快速定位错误和找到你所需要的,如果你不知道你需要查找些什么,参考第一点;堆栈信息的时间很重要,一般的日志都会记录时间,知道异常发生的时间也许帮助你了解很多。
(注:日志的格式是指记录日志的模板,如:时间-线程-类-方法;记录日志的形式,如:按天记载,按账号记载。)

6.使用分析工具,使用Java 提供的分析工具如JMC,Java Visual VM ,可以帮助你分析程序的运行状况如CPU,内存,线程等,这些工具可以用来定位不易发现的内存泄漏问题以及项目后期的优化。

7.查看API文档和GOOGLE,查看官方的API文档可以帮助你更好更快的掌握和使用一个工具类或者框架,记得谁说过:查看官方API文档可以帮助解决80%开发中遇到的问题,剩余的20%你都可以GOOGLE到你想要的答案。

8.如果以上方法均不能解决问题,那么更可能是你把问题想的太复杂,或许应该休息一下。

虽然上面介绍了许多关于定位Bug的方法,但不得不说查找Bug总是费时而且让人头大的,为了避免陷入查找Bug的窘境,请在编写代码的时候谨记墨菲定律:任何可能出错的事情最终都会出错。这点程序上尤为明显。

你可能感兴趣的:(Java)