`
renzhelife
  • 浏览: 668599 次
文章分类
社区版块
存档分类
最新评论

关于解Bug的总结

 
阅读更多
1. 与其他应用交互的Bug
背景:
一个手机音乐播放器,多媒体通常存放在手机外部存储卡上(SDcard上)。所以只有当SD卡Mount到手机上时,才可以播放媒体。音乐播放器就会监听SD卡状态,当SD卡从手上卸载或弹出时,播放器会保存现场并停止播放;当SD卡重新Mount回手机时,再恢复现场和继续播放。也即当播放器收到“SD卡Eject”消息时,停止,当收到“SD卡Mount"时继续播放。播放器可以在后台播放媒体。
一个文件管理器是另外一个应用程序,可以用来编辑(如删除)SD卡上的文件。文件发生变化后,这个第三方应用会发出”SD卡Mount“这样的消息,以便告知其他应用和系统,文件发生了变化。
问题:
当播放器在后台播放媒体的时候,起动文件管理器,然后随便删除一个文件(也可以是正在播放的媒体文件),这时候,播放器停止播放媒体,并且当打开播放器时,发现播放器是处于播放状态的,但是却没有声音。
分析: 播放器不会没有理由的去停止正在播放的媒体。查找发现,播放器停止播放的原因有几个:用户请求停止,切换媒体时,SD卡Eject,SD卡Mount时。经过调试和跟踪日志信息,发现前面三种情况都未发生。那么问题的原因就是SD卡Mount时,进行了恢复现场的操作,导致媒体停止了。那为什么会进行恢复现场的操作呢,因为SD卡并未被Eject和Mount。进一步调试和跟踪日志发现,当文件管理器删除文件后会发出“SD卡Mount”的消息,以便告知其他应用文件发生了变化。
解决方案:
当分析出了问题出现的原因,解决起来就容易了,只需要让播放器在做恢复现场的动作前多一些检测来保证,先前SD卡有Eject过,现在确实是SD卡Mount回来。否则,应该忽略这个消息。
教训:
这应该是软件缺陷引起的Bug,音乐播放器本应该做这样的条件检查。音乐播放器本身的策略是没有错的,当没有其他应用程序发出这样的消息时,它是完全可以正常工作的。这是一个典型的与其他应用或模块交互时产生的Bug。
对于这类Bug,最重要的线索就是,当与其他应用一起操作时会出现问题。这个Bug比较简单,因为很明确是与文件管理器有关。但在有些关系复杂的系统中,当出现了问题,很难搞清是表现问题的模块出了问题,还是其他模块出了问题。这就需要调试跟踪日志,以缩小范围。在调试的时候要一个一个模块的试验和排除,以缩小范围和进一点的深入调查。
2. 原因与问题离的很远的Bug
背景:
一个模块专门负责处理SD卡上的多媒体文件,解析这些文件,获取它们的元信息,并存入到媒体数据库中。它是由Java和C++以JNI方式组合来实现的。Java进行上层流程控制和写入数据库操作;C++负责解析文件获取文件元信息。它们之间通过JNI来通信。
问题:
当处理一个特殊的文件时候Java的JVM(虚拟机)会异常退出(JVM abort),并打印出一条错误信息:"JNI Warning: illegal start byte 0xb1".
分析:
这是一个很严重的错误,因为它会导致JVM崩溃,进程也会被内核杀掉。唯一的线索就是JVM崩溃时打印出的一条信息"JNI Warning: illegal start byte 0xb1".通过搜索这条消息(幸亏有所有的源代码),发现它是由JVM内部的CheckJNI.c文件打印出来的。这个文件是JVM中比较重要的一个文件,它负责对JNI的所有参数进行合法性检查。特别是字串。因为Java中用的是Modified UTF-8编码格式,所以CheckJNI.c文件就会对所传进来的字串进行编码检查,如果字串不是一个合法的Modified UTF-8格式,就会发出警告并停止JVM。这里找到了问题所在,是因为JVM检查到了不合法的字串才导致JVM崩溃的。那么不合法的字串是从哪里来的呢?又是出现在哪个模块呢?因为系统中有无数地方在用到JNI,所以不能盲目的去查找。又由于这是在媒体扫描器扫描某个媒体时候出现的,因此主要目标锁定在媒体扫描器的JNI部分。媒体扫描器的C++部分解析多媒体文件,然后把所得到的结果(通常为字串)通过JNI传回给Java层。问题就很有可能出在这里,因为多媒体文件的信息有多种编码格式,其中元信息就有可能是非法的Modified UTF-8编码格式。经过调试跟踪,发现,确实是这里出现了问题。
解决方案:
这个问题的解决方案仍不是很好,一种方法是对其进行编码转换,但这要知道字串原来的编码方式。另一咱简单的方法就是在传给JNI之前做一次编码合法性检查,以过滤到不合法的字串。最后,采用了后一方式解决了这个问题。
教训:
首先,系统崩溃时所给出的信息和出错时给出的信息是第一重要的线索,虽然它们可能不是问题真正的原因,但是从它们出发就可以追踪到原因。其次,错误信息,是由代码打印出来的,所以当你不知道是哪个模块出错时,可以用错误信息对源码进行局搜索,就可以定位出模块和源码位置。最后,如果是一系列的原因导致了一问题,那么可以在最源头解,也可以其中的某一个环节来解,只要不会导致程序崩溃即可。
3. 空指针异常NullPointerException
背景:
在C/C++/Java中空指针异常是比较常见的一类导致程序崩溃的原因。在C/C++/Java中,如果使用的指针或对象没有正确的初始化,则很容易发生NullPointerException。
问题:
当发生NullPointerException的时候,程序通常会因异常而崩溃的。但通常都会打印出运行时的堆栈信息。
分析:
从程序的堆栈信息,会很容易的看到发生问题的代码位置,这样就可以找到直接原因。但是这找到问题的一小部分,具体是什么导致对象为空,这就不是那么容易调查出原因了。
解决方案:
对于这类问题,一开始能想到的办法就是加上对空指针的检测,如果指针或对象为空的话就不对其进行操作。但这是行不通的,这也不是正确的解决方法,最直接的问题就是,当指针为空的时候应该去做什么。如果在一个类中,在其他地方引用的时候都做了空指针检测,而这个地方没有做,那么可以仿照其他地方那样,加上空指针检测。但假如不是这样的情况,就要好好的调查一下指针为什么会是空,而非处理空指针。但这通常都是比较困难的,因为要去追踪对象是从哪里来的,又在哪里被修改和引用,是在哪里初始化的。只有找到了真正让对象为空的原因,才能算是比较完整的解决了问题。但如果一个比较复杂的系统,引用的地方很多,且假如又涉及到多线程时,则追踪起来会更加的困难。
教训:
对于空指针问题,不能简单的加上一个条件。要进一步的深入去调查是什么导致了指针为空。除非,你有充足的理由去加上条件。
4. 无解的问题
案例一:
背景:
有些问题是极及诡异的,而且出现的机率非常的小,但它们还是会出现,但是找不到合适的解决方案。
问题:
在一个GUI系统中,在一个比较基础的类里面报出了一个NullPointerException。由于这个类会被很所有涉及GUI的应用程序所使用。
分析:
根据程序退出时打印出来的堆栈信息,找到了发生异常的代码位置。令人感到惊讶的是,这一行是绝不可能发生空指针的,因为它用的都是基本数据类型。上下几十行之内也是绝不可能发生NullPointer的。
解决方案:
这个问题,始终没有找到解决方案。
案例二:
背景:
对一个系统做大规模的随机压力测试。一个对象的类Message是一个final的类,且其重载了toString()方法,它会按如下格式打印信息:"{ what=XXX when=XXX XXXXXX }"
问题:
在一次测试过程中,系统核心进程因异常退出,导致系统自动重启。
分析:
问题的原因是在核心进程中发生了一个RuntimeException,并有一条消息:"[c0x44bc: This message is already in use."。从堆栈找到退出的位置的代码,发现它是程序检测到不合理的操作然后抛出的一个RuntimeException:代码如下:
// ...
if (msg.when != 0) {
throw new RuntimeException(msg + " This message is already in use.");
}
// ...
这里的msg是一个Message的对象。
通常来讲+会调用对象的toString()方法,而toString()方法的输出又有特定的格式,所以,这里就发生了让人极其迷惑的事情。因为最终打印出来的消息跟对象的toString()有很大的差别。从日志信息来看,当前对象应该是一个char数组,而并非一个Message对象,但是在相关的上下文都无法找到这样一个char数组。
解决方案:
这个问题,怀疑是对象的内存已被破坏,其内的数据已不再是对象本身。这也是一个没有解决方案的问题。
教训:
这类问题是真正的难题。需要对语言和系统达到精通的人物才可能解的了。
5. 难重现的必现问题
背景:
一个Gallery应用程序能够以网格形式显示很多张图片。当图片较多时,就会在左边出现滑块用来滚动屏幕。正常来讲,当打开应用时,这个滑块应处在最上面的位置。
问题:
有人报告说初始打开应用时,滑块不是在最上面,而是在中部,或其他地方。而且声称这是必现的问题。
分析:
但当调试的时候却怎么也无法重现这个问题。虽然这并不是一个严重的问题,但感觉这样的行为是很诡异的。在调试的过程中,发现,测试人员的应用与我这边应用显示图片的顺序似乎有些不同,是正好相反的顺序。这是有一个可配置的选项在控制的,所选项设置为正序或倒序。发现测试人员当时用的倒序,而通常大多数情况下,用的都是正序(可能是因为没有人去设置这个东西,它默认的是正序)。这可能是问题产生的原因。果然,当把顺序设置为倒序的时候,滑块的位置就不会置顶了。
解决方案:
找到了问题的重现规律,对于这种问题就好办了。发现,当设置为倒序的时候,代码的本意是想把滑块放在最后,但是计算时有些错误,误把一个屏幕窗口的高度当成整个文档长度了。所以当,整个文档长度超过一个屏幕时,滑块的位置就不正确了。由于,把滑块放在最上端的更符合一般情况,所以就无论排序顺序,把滑块置顶。
教训:
事实上,很少问题是真正的小概率事件(Seldom),只有当涉及多个线程的时候才会有真正Seldom的问题,因为无法确定线程的执行顺序。对于其他的问题,应该是都还没有找到重现的规律。相信了这一个事实以后,就要不断的去试验和假设以重现问题。在试验的时候,也要注意细节,因为很多细节都可能是一条重要线索。最重要的是要相信问题是存在的,是可以重现的,更是可以解决的。
有一些方法技巧可以用来重现看似比较难重现的问题:
1. 仔细询问或查看问题出现时的相关操作和日志,以确定是否漏掉了一些必要的前提条件和操作
2. 如果涉及与其他应用或模块交互,则要了解每个应用和模块的特性,然后做适当的假设,再去做试验。
3. 猜测可能导致问题的原因,然后去创造这些条件,看在有这些条件的情况下,是否可以重现问题。比如,如果猜测是时间长短或文件大小导致了问题,那么就可以调大时间,用大文件来测试。如果猜测是空指针的问题,那么就可以故意创造出一个空指针等等。
4. 要相信问题是存在的,也要相信问题是可以重现的,更要相信这个问题是可以修复的。
5. 要有耐心,不断的思考,假设,然后去验证,一次改变一个条件,一点一点的分析与验证,最终是能够重现并修改问题的。
6. 真正难重现的问题----线程问题
背景:一个手机音乐播放器支持多个播放列表,当删除播放列表的时候,如果其中有正在播放的歌曲,那么当删除这个播放列表后,是不会再继续播放。在删除过程中,如果删除到正在播放的歌曲时,会打开并播放播放列表中的下一个歌曲,直到播放列表中的所有歌曲都删除完。删除歌曲的动作是放在与播放不同的线程。
问题:有些时候,删除含有正在播放歌曲的播放列表后,当前歌曲跳到了其他播放列表继续播放
分析:删除过程中会涉及到很多个过程:停止,找到下一首,播放,和删除,如果每一次都这么走的话,是不可能出现这个问题的。经过大量的调试与跟踪,最终发现,是由于停止和播放没能一次执行完,中途被打断。因为删除是在另一个线程中,因此有可能当正在执行停止的时候,TaskScheduler切换了线程,执行了播放,从而切换到了另外的播放列表。
解决方案:找到了问题的原因,解决起来就很容易了,加上同步锁,让删除,停止和播放的每一个过程都保证不被中断,就解决了这个问题。
教训:这是一个真正的随机出现的问题,因为它是由于线程引起的。多线程带来的第一个问题就是不确定性,另外一个问题就是同步与共享的问题。如果没能很好的处理同步与共享,那么多线程会带来更多的问题,远多于它们所解决的问题。

分享到:
评论

相关推荐

    WinCE ZIP 压缩解压缩源代码

    支持缓冲区 文件的zip格式压缩解压缩 内有main.c示例代码 内有bug.txt 总结两个新手容易遇到的问题(本人也是新手呵呵,在使用过程中发现的两个问题,总结了解决方案)

    HD Tune v3.50 完美破解汉化专业版,并修正官方重大错误(MyCrack吐血力作)(转自嬴政)

    说了这么多,总结一下我的版本特点: 1,完美汉化,输出报告也是100%汉化,并且一些其他汉化版从来没解决的摄氏度(任务托盘)问题也解决了! 2,完美破解,所有功能齐全,完美解决其他破解版认不到某些硬盘参数的...

    最新前端调试笔记

    前端调试笔记,总结的很全面,可以参考一下(学会解bug才是真才实学)

    EDiary电子记事本

    ·增加:日记附录加上了"大事记载"和"今日总结"; ·增加:修改天气时,自动修改文本中的日记题头; ·增加:登录框中,如果用户选择了文件,则自动填写用户名; ·增加:工具菜单中加上了“建立快捷方式”; ·增加:...

    映泰HIFI h170Z3 上笔记本cpu 6789代及服务器1151cpu BIOS

    QL2X QL3X 比较特殊 均为7...当然以下方法是搜索相关资料和少量测试(主要为微星、华擎、七彩虹等100系主板)总结出来的,可能存在一些BUG,并不一定是最优解,仅供参考。 大概流程为:添加微码→替换合适的me→关闭me

    python36patterns:最全python36种设计模式。opp和oop的极致使用方式,一切编码思维逃不出这36计

    不愿意学oop和设计模式,天天加班写bug解bug无限复制粘贴扣字老代码写新代码,这种写法瞎忙也没用。 比如韩信3万军队歼灭70万大军,靠的不是大无畏的胡乱冲刺,而是因为韩信看了孙子兵法36计兵书,靠的是策略,所以...

    深入理解Android:卷I--详细书签版

    4.3.3 关于SystemServer的总结 83 4.4 zygote的分裂 84 4.4.1 ActivityManagerService发送请求 84 4.4.2 有求必应之响应请求 86 4.4.3 关于zygote分裂的总结 88 4.5 拓展思考 88 4.5.1 虚拟机heapsize的限制 ...

    asp.net知识库

    .NET关于string转换的一个小Bug Regular Expressions 完整的在.net后台执行javascript脚本集合 ASP.NET 中的正则表达式 常用的匹配正则表达式和实例 经典正则表达式 delegate vs. event 我是谁?[C#] 表达式计算引擎...

    芒果网络考试系统 v4.8.3.zip

    芒果网络考试系统适用于各种考试场合,具有强大的网络功能,支持远程考试和远程考务管理。 芒果网络考试系统功能特点 1、方便、灵活、开放的...2、修复操作题中windows题目不能生成步骤的bug 芒果网络考试系统截图

    leetcode分类-leecode_practice:兔系leecode的刷题记录。用于商业用途请联系作者

    bug-free 解题思路 反转:比如 LeetCode5 建立映射表:比如 LeetCode12, LeetCode13 扩大范围,比如 int 变为 long,解决溢出问题的通用解法 参考 极客时间 《数据结构与算法》 王争 当前进度 没有详细给出题目分类...

    网站网络安全应急救援预案.doc

    (四)系统类故障 指系统由于长时间运行或系统存在的bug造成不能正常运行。 1、相关负责人要每月对数据进行备份,并刻录光盘进行存档。 2、发现此类问题,要报告中心主任,并联系维护单位进行检测修复。 三、应急...

    传智播客扫地僧视频讲义源码

    24_学员二级指针代码bug调试_传智扫地僧 源码及文档 01_课程回顾 02_解密作业 03_指针用法杂项 04_再谈多级指针做输出_传智扫地僧 05_动态库的基本概念和使用 06_动态库测试环境和调试环境搭建 07_socketclient动态...

    vc++ 开发实例源码包

    13:自动报告bug,建议等. 14:宏功能. 15:自动同步文件夹. 16:保存加载任务. 17:计划任务. 18:单线程下载时不能创建临时文件. 19:下载流文件(rm,Media Player). Notepad++ V5.6.8 源码! 如题。 OA精灵代码 c++版 ...

    C#微软培训资料

    14.4 继承中关于属性的一些问题.169 14.5 小 结 .172 第四部分 深入了解 C#.174 第十五章 接 口 .174 15.1 组件编程技术 .174 15.2 接 口 定 义 .177 15.3 接口的成员 .178 15.4 接口的实现 .182 ...

Global site tag (gtag.js) - Google Analytics