记一次JMeter内存不足

问题背景

  • 压测的业务存在多个返回情况,其中认为true的response有两种,认为false的有三种,具体如下
    avatar
  • 需要在jmeter.log中记录下Assert false时的线程信息,如当前活跃的线程数
  • 需要把exception的信息和error的信息分别保存到文件中

问题描述

  • 这种背景下只能选择BeanShell来处理断言、保存信息以及打印特定log了,于是有了下面第一版beanshell
    import com.alibaba.fastjson.JSON;  // 阿里的jar包
    import com.alibaba.fastjson.JSONObject;
    import java.util.Date;
    import java.text.SimpleDateFormat;
    
    void write2File(String data, String path){
        // 该方法用来写入内容到文件,并加上时间
        String tm = (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")).format(new Date());
        FileWriter fstream = new FileWriter(path, true); //FileWriter("file01.txt",true) append mode
        BufferedWriter out = new BufferedWriter(fstream);
        out.write("[" + tm + "] " + data);
        out.write(System.getProperty("line.separator"));
        out.close();
        fstream.close();
    }
    
    if ("200".equals(""+ResponseCode) == false ){
        var errorFile = "errorFile.txt";
        write2File(prev.getResponseDataAsString(), errorFile);  // 写入error信息到errorFile.txt
        Failure=true ;  // 设置断言为false
        FailureMessage ="Exception,fail! Response code is " + ResponseCode;  // 设置断言message
        // 打印log,ctx.getThreadNum()代表当前线程,ctx.getThreadGroup().getNumThreads()代表当前活跃的总线程数
        log.warn(FailureMessage + ". Current threadNum is " + ctx.getThreadNum() + " of " + ctx.getThreadGroup().getNumThreads());
    }else{
        var respBody = prev.getResponseDataAsString();
        // 因为response是JSON格式,这里用JSON包处理
        JSONObject respJson = JSON.parseObject(respBody);
        if (respJson.containsKey("data")){
            Failure=false;
            FailureMessage = "Return true, and the response code was " + ResponseCode;
        }else if (respJson.containsKey("x")){
            var x = respJson.getString("x");
            if (x.contains("connection issue")){
                var issueFile = "issueFile.txt";
                write2File(x, issueFile);
                Failure= true;
                FailureMessage= "connection issue,fail!";
                log.warn(FailureMessage + " Current threadNum is "+ ctx.getThreadNum() + " of " + ctx.getThreadGroup().getNumThreads());
            }else{
                var exceptionFile = "exceptionFile.txt";
                write2File(x, exceptionFile);
                Failure=false;
                FailureMessage = "Return exception, and the response code was " + ResponseCode;
            }	
        }else{
            Failure= true;
            FailureMessage= "Unknow error: " + respBody;
            log.warn(FailureMessage + ". Current threadNum is "+ ctx.getThreadNum() + " of " + ctx.getThreadGroup().getNumThreads());
        }
    }
    
  • 本地调试正常,开心的推到负载机上执行,但是压测时总会出现“内存转储”的现象,即生成hprof文件,比如java_pid3736.hprof
  • 既然内存不足,那就增加JVM内存嘛,于是修改了JMeter启动文件设置
    set HEAP=-Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m
    
  • 发现还是会内存不足,那就分析下转储文件吧(用Memory Analyzer分析)
    avatar
    • 问题很明显了,beanshell内容开销过大

尝试解决

  1. 把if判断改成switch:不记得从哪个大神那里看来的说switch比if节省资源
  2. 把写信息到文件的操作去掉
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    
    switch (ResponseCode){
        case "200":
            var respBody = prev.getResponseDataAsString();
            JSONObject respJson = JSON.parseObject(respBody);
            int f = respJson.containsKey("x") ? 0:1;
            switch (f){
                case 1:
                    Failure=false;
                    FailureMessage = "Return true, and the response code was " + ResponseCode;
                    break;
                case 0:
                    var x = respJson.getString("x");
                    if (x.contains("connection issue")){
                        Failure= true;
                        FailureMessage= "connection issue,fail!";
                        log.warn(FailureMessage + " Current threadNum is "+ ctx.getThreadNum() + " of " + ctx.getThreadGroup().getNumThreads());
                    }else{
                        Failure=false;
                        FailureMessage = "Return exception, and the response code was " + ResponseCode;
                    }
                    break;
                default:
                    Failure= true;
                    FailureMessage= "Unknow error: " + respBody;
                    log.warn(FailureMessage + ". Current threadNum is "+ ctx.getThreadNum() + " of " + ctx.getThreadGroup().getNumThreads());
                    break;
                }
            break;
        default:
            Failure=true;
            FailureMessage ="response error, code was" + ResponseCode;
            log.warn(FailureMessage + ". Current threadNum is " + ctx.getThreadNum() + " of " + ctx.getThreadGroup().getNumThreads());
            break;
     }
    
  3. 再次执行就没有问题了
posted @ 2020-10-09 16:01  z417  阅读(499)  评论(0编辑  收藏  举报