这是一个通用问题,用于帮助那些程序出现问题但不知道如何使用调试器诊断问题原因的新程序员。
这个问题包括三类更具体的问题:
调试器是一个可以在程序运行时检查程序状态的程序。技术手段,它使用这样做对于理解使用调试器的基本知识是不必要的。当程序到达代码中的特定位置时,可以使用调试器暂停程序的执行,然后检查程序中变量的值。可以使用调试器非常缓慢地运行程序,一次运行一行代码(称为 一步一个脚印) ,同时检查其变量的值。
调试器是帮助诊断程序问题的非常强大的工具。并且调试器可用于所有实用编程语言。因此,能够使用调试器被认为是任何专业或狂热的程序员的 基本技能。使用调试器 你自己被认为是 基本工作,你应该做 你自己之前,请求他人的帮助。由于这个网站是为专业和热心的程序员,而不是一个帮助台或指导网站,如果你有一个问题与一个特定的程序的问题,但没有使用调试器,你的问题很可能被关闭和投票否决。如果你坚持问这样的问题,你最终将被阻止发布更多。
通过使用调试器,您可以发现变量是否具有错误的值,以及在程序中哪里将其值更改为错误的值。
使用单步执行还可以发现控制流是否如您所期望的那样。例如,if分支是否在您期望的时候执行。
if
使用调试器的细节取决于调试器,在较小程度上取决于所使用的编程语言。
可以将调试器 接上到已经运行程序的进程。如果你的程序卡住了,你可以这样做。
实际上,从一开始就在调试器的控制下运行程序通常更容易。
通过指示程序应该停止执行的源代码文件和行号,或者通过指示程序应该停止的方法/函数的名称(如果希望在执行进入方法后立即停止) ,可以指示程序应该停止执行。技术意味着调试器用来使程序停止的过程称为 断点,而这个过程称为 设置断点。
最 现代调试器是 IDE 的一部分,并提供了一个方便的图形用户界面检查源代码和变量的程序,与点击界面设置断点,运行您的程序,并单步执行它。
除非程序可执行文件或字节码文件包括调试 符号资料和对源代码的交叉引用,否则使用调试器会非常困难。您可能必须使用 编译(或重新编译)您的程序略有不同来确保信息的存在。如果编译器执行大量优化,那些交叉引用可能会变得混乱。因此,您可能必须使用 在关闭优化的情况下重新编译程序。
我想补充的是,调试器并不总是完美的解决方案,也不应该总是调试的首选解决方案。下面是一些调试器可能无法为您工作的情况:
在所有这些情况下,要么让您的程序突然停止可能会导致最终结果不同,要么手动逐行搜索引起 bug 的那一行太麻烦了。无论 bug 是错误的行为还是崩溃,这种情况都可能发生。例如,如果内存损坏导致崩溃,那么当崩溃发生时,距离最初发生内存损坏的地方太远了,没有留下任何有用的信息。
那么,还有别的选择吗?
最简单的就是记录和断言。在不同的位置向程序添加日志,并比较所获得的内容和所期望的内容。例如,看看您认为存在 bug 的函数是否一开始就被调用了。看看方法开始处的变量是不是你想的那样。与断点不同,存在许多没有发生特殊情况的日志行是可以接受的。您可以随后在日志中进行简单的搜索。一旦你碰到一条与你期望的不同的日志线,在同一区域添加更多。把范围缩小得越来越小,直到能够记录窃听区域的每一条线。
断言可以用来在错误值出现时捕获它们,而不是一旦它们产生了终端用户可见的效果。您越快捕捉到一个不正确的值,就越接近产生该值的行。
重构和单元测试。如果您的程序太大,那么一次测试一个类或一个函数可能是值得的。给它输入,然后查看输出,看看哪些不是您所期望的。能够将一个 bug 从整个程序缩小到单个函数可以在调试时间上产生巨大的差异。
在出现内存泄漏或内存跳转的情况下,使用能够在运行时分析和检测这些问题的适当工具。能够检测到实际腐败发生的地方是第一步。在此之后,您可以使用日志返回到引入错误值的位置。
记住,调试是一个倒退的过程。你得到了最终的结果——一个错误——并找到了它之前的原因。它是关于向后工作的,不幸的是,调试器只能向前进行调试。这就是良好的日志记录和事后分析可以提供更好结果的地方。