什么是debugging器,它如何帮助我诊断问题?

这旨在成为一个通用的问题,以帮助有程序问题的新程序员,但不知道如何使用debugging器来诊断问题的原因。

这个问题涉及两类更具体的问题:

  • 当我运行我的程序时,它不会产生我期望input的输出
  • 当我运行我的程序时,它崩溃,给我一个堆栈跟踪。 我已经检查了堆栈跟踪 ,但是我仍然不知道问题的原因,因为堆栈跟踪没有提供足够的信息。

debugging器是一个可以检查程序状态的程序。 它所使用的技术手段对理解如何使用debugging器的基础知识并不重要。 当程序到达代码中的特定位置时,可以使用debugging器来暂停程序的执行,然后检查程序中variables的值。 您可以使用debugging器以非常缓慢的速度运行您的程序,一次一行代码(称为单步执行 ),同时检查其variables的值。

通过这样做,您可以发现variables是否有错误的值,以及程序中的值是否改变为错误的值。

使用单步执行,您还可以发现控制stream是否如您所期望的那样。 例如,当你期望它应该是执行一个if分支。

使用debugging器的具体细节取决于debugging器以及程度较低的编程语言。

  • 您可以debugging程序附加到已经运行程序的进程。 如果你的程序卡住了,你可能会这样做。

  • 在实践中,从一开始就在debugging器的控制下运行程序通常更容易。

  • 通过指示执行应该停止的行的源代码文件和行号,或者通过指出程序应停止的方法/函数的名称来指示程序应该停止执行的位置(如果要停止一旦执行进入该方法)。 debugging器用来使程序停止的技术手段称为断点 ,此过程称为设置断点

  • 大多数现代的debugging器都是IDE的一部分,并为您提供了一个方便的graphics用户界面,用于检查程序的源代码和variables,以及用于设置断点,运行程序和单步执行的点击式界面。

  • 除非您的程序可执行文件或字节码文件包含debugging符号信息,否则使用debugging器会非常困难。 您可能需要稍微不同地编译(或重新编译)程序以确保信息存在。

我想补充说的是,debugging器并不总是完美的解决scheme,不应该总是作为debugging的解决scheme。 以下是一些debugging器可能不适用于您的情况:

  • 你的程序失败的部分真的很大(可能模块化不佳),而且你不确定从哪里开始单步执行代码。 逐步完成这一切可能太费时。
  • 你的程序使用了很多的callback函数和其他非线性stream量控制方法,这使得debugging器在执行时会感到困惑。
  • 你的程序是multithreading的。 或者更糟糕的是,你的问题是由于竞争条件造成的。
  • 有错误的代码在错误出现之前会运行很多次。 在主循环中这可能是特别有问题的,或者更糟的是,在物理引擎中,问题可能是数字的。 即使设置一个断点,在这种情况下,只会让你打多次,而不会出现错误。
  • 您的程序必须实时运行。 这是连接到networking的程序的一个大问题。 如果你在你的networking代码中设置了一个断点,那么另一端就不会等你一步一步完成,它只会超时。 依靠系统时钟的程序,例如带有跳帧的游戏,也不会好得多。
  • 你的程序执行某种forms的破坏性行为,比如写文件或发送电子邮件,你想限制你需要运行的次数。
  • 你可以知道你的错误是由错误的值到达函数X引起的,但你不知道这些值是从哪里来的。 不得不一遍又一遍地执行程序,将断点设置得越来越远,这可能是一个巨大的麻烦。 特别是如果函数X在程序中的很多地方被调用。

在所有这些情况下,不pipe是让程序突然停止,都可能导致最终结果不同,或者手动search导致错误的一行代码。 无论你的bug是不正确的行为,还是崩溃,这同样会发生。 例如,如果内存损坏导致崩溃,那么在崩溃发生的时候,内存损坏首先发生的地方就太远了,没有有用的信息。

那么,有什么select?

最简单的就是简单的日志和断言。 在不同的地方将日志添加到您的程序中,并将您得到的结果与您所期望的结果进行比较。 例如,看看你认为哪里有一个错误的function,甚至被称为首先。 看看方法开始的variables是否是你认为的那样。 与断点不同的是,没有什么特别的事情发生,有很多的日志行。 之后您可以简单地search日志。 一旦你点击一个不同于你期望的日志行,在同一个区域添加更多。 将其缩小得越来越远,直到足够小,才能够logging每个线路。

断言可以用来捕获不正确的值,而不是一旦它们对最终用户有明显的影响。 越快捕获一个不正确的值,越接近产生它的线。

重构和unit testing。 如果程序太大,一次testing一个类或一个函数可能是值得的。 给它的input,看看输出,看看哪些不是你所期望的。 能够将整个程序中的一个bug缩小到单个函数可以在debugging时间上产生巨大的差异。

在内存泄漏或内存跺脚的情况下,使用适当的工具,可以在运行时分析和检测这些工具。 能够发现实际腐败发生的地方是第一步。 在此之后,您可以使用日志回到引入错误值的位置。

请记住,debugging是一个倒退的过程。 你有最终的结果 – 一个错误 – find它之前的原因。 这是关于如何逆向工作,不幸的是,debugging器只能前进。 这是良好的日志logging和事后分析可以给你更好的结果。