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

找bug记(2)

阅读更多


找bug记(2)

    这篇blog迟到了很久,本来是想写另一个跟网络相关bug的查找过程,偷偷懒,写下最近印象比较深刻的bug。这个bug是我的同事水寒最终定位到的。    前几个月同事报告称有一个线上MQ集群会同一时间抛出ArrayIndexOutOfBoundsException这个异常,也就是数组越界。查看源码,除去一些无关紧要的细节大概是这样子:public class ConnectionSelector{    private AtomicInteger sets=new AtomicInteger(0);   public void selectConnection(List<Connection> connList){          if(connList==null){                return null;           }          final int size = connList.size();            if (size == 0) {                return null;            }           return connList.get(sets.incrementAndGet() % size);}   }    很显然,这里的本意是实现一个轮询的连接选择器,返回一个选中的连接。使用AtomicInteger递增并对链表大小取模,返回结果索引位置的连接。异常抛出的位置就是我代码中标红的位置。    显然,这里有两种可能,一种情况下是说在执行那一行代码的时候,connList的大小缩小了(也就是说连接可能被其他线程移出),那么导致取模的结果越界。另一种可能是取模的结果本身确实超过了列表范围。    第一种情况是完全可能的,因为服务器的连接可能随时断开或者重连,但是这种情况相对非常少见,因此我们这里并没有对这个选择过程做同步,主要是从性能的角度出发,偶尔的失败可以接受。很遗憾的是,我被我的思维惯性误导了,从来没有怀疑过第二种情况,总是认为是不是真的连接恰巧断开导致这个异常,但是却无法解释这个异常发生后就一直错误下去,无法自行恢复。    为什么说思维惯性误导呢?这里的问题其实是负数取模的问题,对一个负数进行取模,结果会是正数还是负数?答案是结果因语言而异。    我很早以前在使用Ruby的时候做过测试,负数取模结果为正数,例如在irb里尝试下:>> -1000%3=> 2>> -2001%4=> 3    这个印象持续至今,在clojure里结果也是这样子:Clojure 1.2.1user=> (mod -1000 3)2user=> (mod -2001 4)3    可以再试试python:Python 2.7.1 (r271:86832, Jun 16 2011, 16:59:05) [GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwinType "help", "copyright", "credits" or "license" for more information.>>> -10000%32>>> -2001%43    这三种语言的结果完全一致,结果都为正数。这个惯性思维延续到java却不成立了,可惜我根本没做测试,让我们试下:   public static void main(final String[] args) {        System.out.println(-1000 % 3);        System.out.println(-2001 % 4);    }打印结果为:-1-1    果然,在java里负数取模的结果为负数,而不是我习惯性地认为是正数。因此最终的定位到的原因就是sets这个变量递增超过Integer.MAX_VALUE后越界变成负数了,取模的结果为负数,导致抛出数组越界的异常,这也解释了为什么同一个集群都在同一时间出问题,因为这个集群内的机器启动时间相邻并且调用这个方法次数相对平均。修正问题很简单,加个Math.abs就好。    Update:加个abs是不够的,因为Math.abs的javadoc提醒了:Note that if the argument is equal to the value of Integer.MIN_VALUE, the most negative representable int value, the result is that same value, which is negative.     也就是说对Integer.MIN_VALUE做abs结果仍然是负数。尽管在这个场景中失败一次可以接受,但是最好的办法还是回复中steven提到的抵消符号位的做法:(sets.incrementAndGet() &amp; 0x7FFFFFFF) % size        这个问题更详细的讨论后来我找到这篇博客,作者讨论几种语言和计算器的这个问题的结果,给出了一些结论。不过我觉的这个结论可能也不是那么可靠,特别是对c/c++来说,很大程度上应该还是依赖于实现,最可靠的办法还是强制结果为正。    这个bug的几个教训:1、首先是第一次出现的时候没有引起足够重视,重启解决问题后没有深究。有句玩笑话:99%的程序问题都可以通过重启解决。但是事实上问题仍然存在,该发生的终究还会发生。不管你信不信,它就是发生了,这是一个奇迹。2、注意大脑的思维惯性,经验主义和教条主义都不可取。最近在读一本好书《暗时间》,大脑误导我们的手段可是多种多样。3、最后就是这个负数取模的结果因语言而异,不要依赖于特定实现。  

posted on 2011-09-02 00:02 dennis 阅读(2535) 评论(5)  编辑  收藏  所属分类: java 、工作随笔

2
3
分享到:
评论
2 楼 jyjava 2011-12-05  
你debug调试,应该很快会定位到的
1 楼 xuehua1987 2011-12-05  
上面的方法返回值是void ,怎么可以返回你取到的连接????其实这个Bug是很好的定位的啊。

相关推荐

    bug记录内容,填写模板,通知单描述

    很多不能重现的bug都是因为缺少日志,开发人员就会返回去找测试人员要日志信息。如果日志文件不大的话,比如十几行,那么可以直接把日志信息粘到bug单里,如果日志很大的话,那么最好单独粘到一个文件里,如txt格式...

    BUG跟踪流程

    bug跟踪流程,以图表的形式详细说明了如何发现BUG,回归BUG

    Buggit2000.rar

    6. **报告和统计**:Buggit2000提供丰富的报告和图表,帮助团队分析Bug的趋势,找出常见问题,优化开发流程。 三、Buggit2000的使用 下载并安装名为“Buggit2000.EXE”的程序后,用户即可启动Buggit2000。首次使用...

    java java查bug 查bug bug 查错 源码

    `findbugs-1.3.9`是FindBugs的一个版本,这个工具通过静态分析,能够在不运行程序的情况下找出可能存在的bug。它的分析范围广泛,包括空指针异常、未初始化的变量、资源泄漏等。通过在项目中集成FindBugs,开发者...

    一些bug的知识集

    2. **Bug的分类:** - **语法错误:** 代码中违反了编程语言的语法规则,编译器无法理解,导致程序无法编译。 - **运行时错误:** 代码可以成功编译,但在执行期间出现问题,如除以零、数组越界等。 - **逻辑错误...

    微信小程序开发附源码:关于微信小程序bug记录与解决方法.doc

    利用微信开发者工具提供的真机远程调试功能,可以实时查看和修改元素样式,这对于找出和修复问题非常有帮助。 7. **代码复用和模块化**: 对于常见问题,如上述textarea的适配,可以封装成可复用的组件或函数,...

    禅道bug管理工具

    在“产品管理”和“需求管理”模块,禅道允许团队定义和管理产品的需求和功能,这样在测试阶段就可以依据这些需求来发现与之不符的地方,从而找出潜在的Bug。通过这种紧密的关联,禅道帮助团队保持对软件开发的整体...

    Bugzilla Bug Xml导出为excel

    2. 进入你想要导出的Bug列表页面。 3. 在页面顶部找到并点击“导出”或“Export”按钮。 4. 在弹出的选项中选择XML格式,然后配置其他参数,如筛选条件、字段选择等。 5. 点击“生成报告”或“Generate Report”,...

    bug数据分析

    **原因定位**,通过代码审查、日志分析等手段找出bug的根本原因;**修复策略**,确定最合适的解决方法,是修改代码还是调整设计;以及**预防措施**,通过改进编码规范、增加自动化测试等方式防止类似bug的再次出现。...

    Bug状态流程图

    2. **新建状态**:Bug被首次提交到Bug跟踪系统时,其状态通常为“新建”或“待确认”。此时,系统管理员或负责人会对报告进行初步审核,确保问题的描述清晰且确实存在。 3. **确认与分类**:经过确认后,如果Bug...

    bug管理系统-ssh

    9. **报表和分析**:系统应提供各种报表功能,例如bug趋势分析、解决速率报告等,帮助团队了解bug管理的整体状况,找出问题并持续改进。 通过这样的bug管理系统,团队可以有效地跟踪和解决开发过程中的问题,提高...

    Linux下的bug管理系统

    在调试涉及网络通信的bug时,可能需要使用如tcpdump或Wireshark这样的网络分析工具来捕获和分析网络流量,找出问题所在。 总的来说,Linux下的bug管理系统包括选择合适的工具,了解并熟练使用这些工具的功能,以及...

    Bug管理的经验和实践.rar

    2. **Bug分类和优先级设定**:根据严重程度和影响范围,Bug可以被分为不同类别,如严重、主要、次要等。同时,设定优先级帮助团队决定修复顺序。 3. **Bug追踪**:使用Bug跟踪工具,如JIRA、Bugzilla或GitHub ...

    bugreport、logcat、kernel、anr以及tombstones的log抓取

    开发者可以通过分析ANR日志找出导致程序卡死的原因,如阻塞的线程或长时间运行的操作。 `tombstones`是Android为严重崩溃情况保留的特殊日志。当应用崩溃且无法捕获异常时,系统会生成一个`tombstone`文件,记录...

    缺陷管理工具bugfree

    2. **项目管理**:在BugFree中,你可以创建和管理多个项目,每个项目可以有独立的缺陷库。这样,团队可以针对不同的软件版本或模块进行独立的缺陷跟踪。 3. **权限控制**:系统支持角色和权限设置,确保数据安全,...

    BugReport dump txt

    2. **SSBugReport.cpp**:这个文件可能是用于生成Bug报告的核心代码实现。`SSBugReport`可能是一个类,封装了收集、整理和输出错误报告的功能,包括从`StackWalker`获取的堆栈信息,以及其他可能的系统状态数据。 3...

    Bugfree 2.0

    5. **报告和统计**:系统内置的报表和统计功能可以帮助团队分析Bug趋势,找出问题的根源,从而提高软件质量。 6. **权限控制**:Bugfree 支持角色和权限的精细化管理,可以根据团队结构设置不同的访问和操作权限,...

    软件测试Bug生命周期及其管理

    此外,通过分析常出错的模块,可以进行代码审查,找出潜在的改进点,防止类似问题的再次出现。 最后,Bug生命周期管理的目标是提高软件质量,减少错误,优化开发流程,确保产品按时发布并满足用户需求。有效的管理...

    软件开发BUG描述报告书(22份)软件开发文档打包下载

    2. **Bug分类**:Bug可以按类型分为功能错误、界面缺陷、性能问题、兼容性问题、安全漏洞等。理解这些分类有助于快速定位问题。 3. **Bug状态管理**:从新建到关闭,Bug会经历待确认、已分配、正在处理、已修复、待...

Global site tag (gtag.js) - Google Analytics