zoukankan      html  css  js  c++  java
  • 多么痛的领悟代码优化导致的BUG

    一大早服务器报警,top一下,系统CPU负载已经飚到了15,导致无法访问!
    jstack pid打印堆栈,大量解析json的线程在RUNNABLE。
    忽然想到之前为了json解析的效率,放弃了现成的类库,手动做json解析,这样做的结果是效率提高了50倍以上,当时还沾沾自喜了好一阵子!
    万万没想到今天忽然一条格式不合法的数据,竟然导致了死循环!

    暂且不去说脏数据是如何进入到系统的,看一下解析Json的代码:

    public static List<Long> getPartneridsFromJson(String data){
        //{\"data\":[{\"partnerid\":982,\"count\":\"10000\",\"cityid\":\"11\"},{\"partnerid\":983,\"count\":\"10000\",\"cityid\":\"11\"},{\"partnerid\":984,\"count\":\"10000\",\"cityid\":\"11\"}]}
        //上面是正常的数据
        List<Long> list = new ArrayList<Long>(2);
        if(data == null || data.length() <= 0){
            return list;
        }    
        int datapos = data.indexOf("data");
        if(datapos < 0){
            return list;
        }
        int leftBracket = data.indexOf("[",datapos);
        int rightBracket= data.indexOf("]",datapos);
        if(leftBracket < 0 || rightBracket < 0){
            return list;
        }
        String partners = data.substring(leftBracket+1,rightBracket);
        if(partners == null || partners.length() <= 0){
            return list;
        }
        while(partners!=null && partners.length() > 0){
            int idpos = partners.indexOf("partnerid");
            if(idpos < 0){
                break;
            }
            int colonpos = partners.indexOf(":",idpos);
            int commapos = partners.indexOf(",",idpos);
            if(colonpos < 0 || commapos < 0){
                //partners = partners.substring(idpos+"partnerid".length());//1
                continue;
            }
            String pid = partners.substring(colonpos+1,commapos);
            if(pid == null || pid.length() <= 0){
                //partners = partners.substring(idpos+"partnerid".length());//2
                continue;
            }
            try{
                list.add(Long.parseLong(pid));
            }catch(Exception e){
                //do nothing
            }
            partners = partners.substring(commapos);
        }
        return list;
    }


    注意1处和2处,如果格式不合法就直接进行下一次循环。问题就出在这里,如果partners.substring(colonpos+1,commapos)取出来是空,进入下一次循环的时候没有更改原字符串,下次还会重复执行,导致了死循环!
    很低级的一个失误!Fuck!
    教训:
    (1)不要轻易的优化代码。

    (2)一定要做好单元测试,考虑正常分支和异常分支,正常数据和异常数据。

    (3)CPU负载过高,很可能是出现了死循环!

    ps:看到一个打印堆栈的方法:

    写一个打印堆栈的方法:
    @Path(value = "/api/stackinfo")
    @GET
    public ActionResult stackinfo() {
    	String str = "<strong>Memory:</strong>";
    	str +="<ol>";
    	str +="<li>freeMemory="+Runtime.getRuntime().freeMemory()/(1024*1024)+"M</li>";
    	str +="<li>totalMemory="+Runtime.getRuntime().totalMemory()/(1024*1024)+"M</li>";
    	str +="<li>maxMemory="+Runtime.getRuntime().maxMemory()/(1024*1024)+"M</li>";
    	str +="</ol>";
    	str +="<br/>";
    	str +="<strong>Thread:</strong>";
    	str +="<ol>";
    	for(Thread t : list_threads()){
    		str +="<li>"+t.getName()+","+t.getState()+":"+ t.getClass().getName()+"</li>";
    		StackTraceElement[] elems = t.getStackTrace();
    		str += "<ol>";
    		for(StackTraceElement elem : elems){
    			str +="<li>    "+elem.toString()+"</li>";
    		}
    		str += "</ol>";
    	}
    	str +="</ol>";	
    	beat.getResponse().setContentType("text/html;charset=UTF-8");
    	return new ContentResult(str);
    }
    


  • 相关阅读:
    MVC模式下 provider: SQL Network Interfaces, error: 50
    How to expose a JSON endpoint from a WCF-service
    net 后台任意设置 控件显示和隐藏就OK
    VS编程,快速折叠或者展开代码到 #region 级别的设置方法。
    java进阶(18)--Enum枚举
    java进阶(17)--Random
    java进阶(16)--System常用方法总结
    java进阶(15)--DecimalFormat、BigDecimal
    java进阶(14)--日期时间处理
    java进阶(13)--int、String、Integer互相转换
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/2998526.html
Copyright © 2011-2022 走看看