一、程序的BUG和异常
程序不是发布到生产环境就万事大吉了。没有人敢保证自己写的代码没有BUG,放心,说这种话的人,基本可以断定是小白。如果在开发阶段出现问题,还是比较好解决的,但是如果真到了生产上,可能会有一些限制,导致一些手段无法全部用上。下面就不同的情况进行一下分析。
二、如何调试程序
1、小程序
小程序就非常好说了,特别量些单机的小程序,直接挂上IDE或GDB,下断点调试即可。偶尔遇到一些细节问题,也可以打印输出具体的值(std::cout等)。
2、中型程序
中型程序一般也和小程序差不多,但此时打印日志就比较多了。同时中型程序可能不允许停机,这时就可以使用一些IDE的远程调试工具(类似gdbserver)进行调试,总体来说,在中小规模程序下,IDE和GDB调试等相关的方法还是为主的。其它一些工具,如内存检测工具、资源消耗工具等都是非常少见使用的。
如果遇到崩溃还可以使用coredump直接定位堆栈。基本上中小程序这样就足够了,当然如果能更灵活的使用其它工具更好,不过没有也没啥大问题。
3、大型程序
大型程序就比较麻烦了,一般大型程序不只一个模块,可能分解成多个独立的程序甚至部署在不同的机器上,使用GDB(IDE)调试,一般情况下就比较麻烦了,但也不是不可能,只是比较少见罢了。毕竟IDE的图形界面往往本身就成为一种负担。
大型程序的调试手段基本就全了,资源占用及性能分析工具(gprof等),内存检查工具(cppcheck及valgrind等),coredump分析crash情况等等。但最主要的就是打log,当然能够实时输出print更好,只是可能有的环境不允许。
另外,如果允许,也可以在怀疑的地方进行代码插桩,这种就看具体的场景应用了。
4、不可停止的程序
对于一些在线的服务,24×7运行的,一般不允许停止或者只允许短暂停止。这时,其实最主要的方法就是埋入日志,这是最好的方法。虽然远端调试可以解决不停机的问题,但在调试状态下,程序明显会变慢,而且,往往有的程序在部署时为了效率,进行了很高的优化。如果不是提前做了准备在编译时允许打入符号之类的动作,调试的意义其实也不算多大。
5、其它
其实回过头来,看看每个开发者面对的程序和场景都不一致,可能的是单纯的软件,有的可能要和一大堆硬件通信,有的可能还可能是分布式,等等。所以定位和解决BUG,需要开发者根据实际情况,善于利用各种工具来解决问题。比如和硬件通信,收不到数据,就需要和硬件协调通过各种硬件仪器来监测到底是硬件本身的问题还是固件的问题亦或是接口通信的问题等等。工具非常重要,一定要掌握一些经常使用的工具。
说句实在话,中小程序用调试直接下断点,大程序直接打日志分析,这是最经典也最好用的方法。特别是程序越大,日志的作用越大。不要害怕多线程的情况下日志的输出与实际可能有所不同,只要认真分析日志,总会查找到蛛丝马迹,然后定位问题。在实践中,这种现象非常常见。
三、总结
调试程序并解决问题的速度和经验有相当大的关系,特别是到了具体的场景下,可能大部分情况下经验要大于技术水平。当然,二者肯定是互相影响的。所以,在生产上要想迅速的对问题程序进行调试定位,就一定要掌握好具体环境的特点和性质。其它的好的技术或方法可能在实际场景中被限制使用,所以不能教条的复用它人的经验。
、