定位Bug技巧总结_帅帅的我萌萌哒的博客-程序员宝宝

技术标签: Java  

解决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的窘境,请在编写代码的时候谨记墨菲定律:任何可能出错的事情最终都会出错。这点程序上尤为明显。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/sinat_25141403/article/details/51307360

智能推荐

使用Docker快速部署ELK环境(最新5.5.1版本)_docker修改es配置_gongxsh00的博客-程序员宝宝

本文介绍了如何使用Docker快速部署一个ELK日志采集和分析环境。

layer 复选框反选功能,以及获取复选框的选择状态。_layer 选择_【蓦然回首】的博客-程序员宝宝

其实我用过许多方法,发现layer的复选框用$("#id").checked以及 $(".class").checked等等是无法获取和改变它值的,只能用下面的循环语句获取复选框的选中状态,应该是layer本身把相关事件给屏蔽了吧。//反选         function DoCheck() {            //layui-unselect layui-form-checkb...

Python----Paramiko模块和堡垒机实战_weixin_30485379的博客-程序员宝宝

paramiko模块  paramiko是一个用于做远程控制的模块,使用该模块可以对远程服务器进行命令或文件操作,值得一说的是,fabric和ansible内部的远程管理就是使用的paramiko来现实。其实它的底层是对ssh的上层代码的一个封装一、下载安装123#pycrypto,由于 pa...

Java IO 方式_dxmdxm123的博客-程序员宝宝

Java IO 方式有很多种,基于不同的 IO 抽象模型和交互方式,可以进行简单区分。首先,传统的 java.io 包,它基于流模型实现,提供了我们最熟知的一些 IO 功能,比如 File 抽象、输入输出流等。交互方式是同步、阻塞的方式,也就是说,在读取输入流或者写入输出流时,在读、写动作完成之前,线程会一直阻塞在那里,它们之间的调用是可靠的线性顺序。java.io 包的好处是代码比较简单、直观,缺点则是 IO 效率和扩展性存在局限性,容易成为应用性能的瓶颈。很多时候,人们也把 java.net

请实现一个方法,把字符串中的每个空格替换成 %20 ,例如,输入"We are happy.",则输出"We%20are%20happy."_Lindsay_liu的博客-程序员宝宝

运用所学java编程,自己写一个方法,实现字符串中指定内容的替换,若从头扫描到尾,遇到指定内容时,替换一次,这样整个字符串后面的内容都要往后移动,时间复杂度较高,为了降低时间复杂度,有了如下方法:

随便推点

python leetcode 171-180_一条没有梦想的咸鱼皓的博客-程序员宝宝

# 171class Solution: def titleToNumber(self, s: str) -> int: res = 0 bit = 1 for a in s[::-1]: res += (ord(a) - 64) * bit bit *= 26 return res# 172class Solution: def trailingZeroes(s.

一周入门Python数据分析|实战教学第1天_一周学会python数据分析_普通网友的博客-程序员宝宝

第1天(难度★) (难度持续增加)你也许不用成为数据分析师,但如今在职场中你一定要具备数据思维,培养运用数据的能力,才能充分在工作中掌握主动权。如果你意识到了数据分析的重要性,那就从这里学起来。1.工具:推荐安装使用anaconda,里面的python已经安装好了一大堆工具包。如果要安装第三方库,只要搜索并选择版本就可以一键安装,连pip install命令都不需要,使用非常方便。我这里使用的就是从anaconda里下载的jupyter notebook。2.内容:主要教一些如何使用python.

netty拆包/粘包的解决方案_程序编织梦想的博客-程序员宝宝

netty拆包/粘包的解决方案刚开始学拆包/粘包的时候确实不太好理解,我反复看了几遍就理解了。写下了加深记忆,也希望对大家有所帮助。在文章开头免费为大家送上代码以便大家对照着学习。本章只介绍简单的二个工具LineBaseFrameDecoder和StringDecoder.

运维--Linux下常用指令_HAH-M的博客-程序员宝宝

批量注释1、在 10 - 20 行添加 // 注释:10,20s#^#//#g2、在 10 - 20 行删除 // 注释:10,20s#^//##g3、在 10 - 20 行添加 # 注释:333,34s/^/#/g4、在 10 - 20 行删除 # 注释:10,20s/#//g

Win7 SMTP 服务器代替工具_Joey_Hong的博客-程序员宝宝

在win7下,程序员如果要用到smtp服务器的话,可以用如下的工具代替:http://www.toolheap.com/test-mail-server-tool/

推荐文章

热门文章

相关标签