UE4工程调试简易小结

优化靠猜?解决bug靠蒙?不不不,要靠调试。那么什么是调试呢?本文就如何调试UE4工程简略提提一些概念。

基本概念

Debugging is the process of finding and resolving of defects that prevent correct operation of computer software or a system. Debugging tactics can involve interactive debugging, control flow analysis, unit testing, integration testing, log file analysis, monitoring at the (application or system level, memory dumps, and profiling.

以上是摘自维基百科对调试的释义。值得注意的是维基百科上中文版的解释只包含第一句的“除错”的概念,而英文版却提到了调试过程使用的多种策略,如log文件分析,单元测试等。这些东西往往也是容易被我们不重视的步骤。

为什么要调试

调试是程序员的基本功,厉害的程序员往往其调试功力也会相当的深厚。之前释义中提到的,调试的主要用途是用来除错,且作用远远不只是调错,它还可以在很多方面帮助到我们。

  • 帮助理解代码:当拿到一份陌生且复杂的代码后,我如果直接尝试从全局去掌控代码,往往可能会迷失在茫茫多抽象概念及分层中,然后始乱终弃。如果能提供相关的调试手段,那么不啻于在黑夜中为我点亮一盏路灯。通过断点、单步等操作摸清关节,理出大致脉络,从而快速理解代码。
  • 帮助来优化程序:编程不是玄学。调试靠蒙,优化靠猜是肯定是不靠谱的。正如释义中提到的profiling,可以通过调试的一些手段来帮助优化。UE4本身就提供了大量的profiling相关的宏以及完善的图像化工具,更是支持第三方工具插件。这实际上也是包含在调试中的。

如何进行调试

调试的手段有很多,简单到阅读代码人脑调试,复杂到IDE提供各种调试信息单步执行。说到这里不得不赞叹人类的智慧,我很难想象在复杂的编程中没有IDE的情景。通常使用一个完善的IDE时,我们可以获得相应的call stack、当前可以访问的变量,可以添加断点,可以添加监视,还可以追踪代码执行流程,甚至还可以查看内存信息等。所以当前阶段活用好IDE提供的调试工具基本上就可以满足绝大多数的调试需求了。

如何调试UE4工程(windows + visual studio)

我这里主要说说windows平台下如何使用visual studio来进行调试。但是关于如何使用VS调试的功能我不会累述,因为VS官方提供的资料比我这么只言片语会更系统和详细。我只会提到UE4工程调试过程中需要注意的地方。

调试符号文件

调试符号文件debugging symbol,在VS这边对应.pdb(progra data base)文件。这个就是我们在调试的时候对应到代码运行到哪一行的依据,也就是说如果某段代码缺少相应的pdb文件,那么在调试的时候我们是无法跟踪在这段代码块的内容的。在VS可能连相应的call stack都会显示不全。所以有没有对应pdb是我们能不能使用VS来调试对应代码的决定因素。对于UE4工程这种体量的程序来说,pdb往往会比较大。一般来说pdb文件也不会暴露给一般用户。

UE4安装版和源码编译版调试的区别

通过Epic Game Launcher安装的UE4引擎程序属于安装版,而从github上直接下载相应的源码并编译属于编译版。就调试这边而言,虽然安装版也支持下载相应的pdb文件来帮助调试,但是可能是由于某些设置的问题使得最终打包的程序对于源码部分的代码pdb对应不全,导致最后无法调试源码部分代码。安装版在打包时,工程只会链接成一个可执行程序,相关代码会以静态链接库的方式被我们的工程程序引用,而这个过程中由于某些未知原因没有正确的生成相关的pdb。这一点你可以通过同一个工程分别使用安装版和编译版来打包程序,并且比较其生成的pdb大小来得知(要获得打包程序的pdb,需要在package settings里面勾选输出debug info的选项)。不过就editor中的调试而言,当你下载了相应调试符号数据后,可以比较正常的调试,因为editor用到的各种dll的pdb都是全的。而编译版生成的pdb则相对较全,所以可以正常的进行调试(不包括被优化的代码部分)。

调试时需要注意的地方

上面简单的介绍了下调试的过程,对于调试的细节没有讲,也不想讲,毕竟没有文档讲得详细,粘贴过来也是冗余。但是有些调试的时候遇到的坑或者比较重要的技巧还是需要提出来。

使用VS的Attach to Process来进行调试

直接上一个视频教程:地址

使用dump文件定位bug

当程序崩溃后,在saved目录下会生成相应的dump文件,这种文件包含了对我们在打包后来查错而言的非常宝贵的数据。如果配合之前提到的pdb文件我们能够知道崩溃时的大致现场,比如call stack、variables等,当然这个信息的详细程度是和你提供的pdb和源码的关联程度挂钩的。至于具体怎么使用暂时就不累述,这里只是抛出dump文件这么个概念。

调试的时候注意配置对应

VS中的build configuration.aspx)决定生成工程时的各种配置,包括预处理宏、编译前后的脚本等等。且不同版本生成的pdb也不同。一般来说,editor下选择developement editor,打包程序则是根据你打包时选的是shipping、debugGame、developement来分别对应的。当然还有target platform也需要对应。如果不对应则无法正常断点或者定位到部分相应代码的。另外UE4的工程不是常规的C++工程,我尝试了下使用start debug instnce方式来调试,没有成功。可能是我没有正确设置,后面会继续思考。

调试时你看到的和你想的不一致

编译之后的程序,可能经过了各种优化,导致一些最终编译的代码和源码的不一致。另外在可能缺少一些类型的内存解析的xml导致在显示的可能和你想的不一致。这种问题暂时没有很好解决方法,不过可以使用未优化的版本排查,或者就是加log了。

图形调试工具

这里的提到图形调试工具,我还想表明在某些方面我们可以借助一些第三方的调试工具。比如RenderDoc来进行图形调试,抓包工具来调试网络部分内容。调试不只是局限在IDE中,只要能够帮助你解决问题都是调试手段,所谓“不管黑猫白猫,捉到老鼠就是好猫”。

总结

调试是需要长期积累经验技巧的基本功,也是成为一个高效程序员的必备的能力,我也在且行且学中。这篇文章只是简单提到了一些调试的概念,之后如果有觉得有价值的东西我会继续补充。