你的代码中有没有错误,你无法解决?我希望我不是那里唯一一个有这种经历的人......
存在一些类别的错误,很难追查:
与时序相关的错误(例如,在进程间通信期间发生)
与内存相关的错误(大多数人都知道适当的例子,我猜!!!)
与事件相关的错误(难以调试,因为您遇到的每个断点都会使您的IDE成为鼠标释放/焦点事件的目标......)
依赖于操作系统的错误
硬件相关的错误(发生在发布机器上,但不发生在开发人员机器上)
...
说实话,我不时自己修复这样的错误......经过几个小时(有时甚至是几天)的调试后,我觉得非常士气低落.
在这种情况下你做了什么(除了向别人寻求帮助之外并不总是可行的)?
你呢
使用铅笔和纸而不是调试器
面对另一件事,稍后再回到这个bug
...
请告诉我!
一些有用的东西:
1)休息一下,从不同角度接近虫子.
2)通过跟踪和记录更加积极.
3)让另一双眼睛看着它.
4)通常的最后手段是通过改变它发生的基本条件来找出一种使bug无关的方法
5)粉碎和破坏东西.(只减轻压力!)
我曾经为一家销售客户端服务器应用程序的公司工作,该应用程序基本上是一个文件传输和同步工具.客户端和服务器都是我们设计的自定义应用程序.
我们有一个在实验室中很难复制的持久性错误.我们的服务器每个盒子只能处理一定数量的传入客户端连接,因此我们的许多客户会将多个服务器"集群"在一起以处理大量用户群.群集的后端数据位于他们共享的文件服务器上.在此群集配置中,有一个错误会在加载时发生,我们会在涉及其中一个后端文件的文件共享调用上获得低级文件系统错误代码.没有人能够在实验室中可靠地重复这一点,即使他们能够做到这一点,他们也无法缩小所发生的事情.
(我忘记了确切的错误,它可能59 ERROR_UNEXP_NET_ERR
或者可能65 ERROR_NETWORK_ACCESS_DENIED
.我记得它甚至没有一个记录的错误代码,你应该能够从我们调用的API中获取,这通常是锁定或解锁调用文件部分).
由于它涉及服务器和后端文件存储之间的通信,而我是"网络传输"的人,我的任务是查看它.许多人没有运气地看着它.
我所拥有的一件事就是我知道在代码中检测到错误的位置,但不知道如何处理错误.所以我需要找到根本原因.因此,我设置了一个适当的硬件环境来复制它,并且我提供了一个自定义构建的服务器软件,用于检测相关代码部分.
仪器如下:我为麻烦的错误代码添加了一个测试,并让它调用一段代码,在发生错误时将UDP数据包发送到预定的网络地址.UDP数据包中包含一个唯一的字符串来键入.
然后我在网络上设置了一个数据包嗅探工具.(当时我使用的是Microsoft Network Monitor).我将它定位在能够"发送"UDP数据包的时间,以及集群服务器和文件服务器之间的所有通信.
大多数好的嗅探器都有一种模式,你可以捕获它直到它看到特定的流量,然后停止.我打开该模式并将其设置为查找我的代码将发送的UDP数据包.目标是在错误发生之前最终获得所有文件服务器流量的数据包捕获.进出UDP数据包的系统的最后一个网络数据包可能是发生了什么的一个重要线索.
我设置了"压力测试"配置,并在周末回家.
当我星期一回来的时候,我看到了我的数据.经过几个小时的运行后,嗅探器已按预期停止并包含捕获.在研究捕获之后,我发现由于服务器上的极端负载,我们的服务器和文件服务器之间的服务器消息块或SMB(也称为CIFS又名SAMBA)连接实际上在TCP级别超时.因为所有微软的东西都是分层的,所以它会通过文件共享堆栈进行备份,作为"意外"错误,而不是返回一个更容易理解的错误代码,说"嘿,你在TCP级别丢失了连接".
我对Windows的TCP设置做了一些研究,并且看到我们使用的Windows版本(那个时代可能是NT 4)的默认值都不是很慷慨.它只允许在TCP连接和繁荣时出现极少数故障,你已经死了.一旦丢失了与文件服务器的SMB连接,所有文件锁都是吐司,无法恢复.
所以我最后在用户手册中编写了一个附录,解释了如何在Windows中更改TCP设置以使您的群集服务器更容忍高负载情况.就是这样.该错误的修复是代码零更改,只是一些关于如何正确配置操作系统供本产品使用的其他文档.
我们学到了什么?
准备好运行代码的更改版本来调查问题
考虑使用非传统工具来解决问题(嗅探器)
并非所有错误修复都需要更改代码
有时你可以在家里喝啤酒时诊断出虫子
我做了很多不同的事情:
抛弃我所有的假设,从头开始.请记住,存在一个错误,因为看似正确的东西实际上是错误的.即使是您绝对确定的那些行或函数或类也可能不正确.直到你能说服自己的正确性,你才能认为一切都是正确的.
继续使用打印语句和断言语句以消除事物,并允许我改革新的假设.
如果问题是控制流问题,请在调试器中逐步执行代码.不要跨越功能.介入它们并完成执行的所有细节,以确认它们正常工作.确认参数并返回值.
如果一行或函数或类是可疑的,但我不能在原位证明它,那么写一个小的测试用例,做你认为问题构造做的事情.这可能会找到问题或提供一些见解,以了解下一步的位置.
停下来过一天.令人惊讶的是,你的大脑将在一夜之间做什么样的离线处理.通常情况下,答案或关键洞察力会出现在第二天,而我正在做一些像洗澡或开车一样无知的事情.
创建一种导致错误的自动方式.要修复的最糟糕的错误是需要数小时才能重现的错误.
报价取自" The Cryptonomicon ":
"直觉,就像一道闪电,持续一秒钟.通常是在一个人被一个困难的解密折磨,当一个人在他的脑海中回顾已经尝试过的无结果的实验时.突然间,光线突然出现,一个人发现了一些前几天劳动无法透露的分钟."
我经常要求别人看看代码.虽然我在解释代码应该做什么,但我有时会在谈话时看到错误.
当一个bug是一个很难的时候,我坐下来工作直到我搞清楚并解决问题.有趣的是,有时候捕捉一个神秘的bug比一切顺利运行更令人愉快.当一个错误得到解决时,缓解和感觉,好吧,没有多少其他东西可以击败它(除了明显的错误).