【问题标题】:Caliper : JVM throws OutOfMemoryError Exception卡尺:JVM 抛出 OutOfMemoryError 异常
【发布时间】:2012-08-29 05:10:14
【问题描述】:

我正在使用 google caliper 对一种方法运行一个非常简单的基准测试。我收到以下异常。

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at com.code4refernce.caliper.SimpleCaliperTest.timeStringLen(SimpleCaliperTest.java:24)
    at sun.reflect.GeneratedMethodAccessor2.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:616)
    at com.google.caliper.SimpleBenchmark$1.run(SimpleBenchmark.java:125)
    at com.google.caliper.TimeMeasurer.measureReps(TimeMeasurer.java:174)
    at com.google.caliper.TimeMeasurer.warmUp(TimeMeasurer.java:62)
    at com.google.caliper.TimeMeasurer.run(TimeMeasurer.java:122)
    at com.google.caliper.InProcessRunner.run(InProcessRunner.java:74)
    at com.google.caliper.InProcessRunner.run(InProcessRunner.java:49)
    at com.google.caliper.InProcessRunner.main(InProcessRunner.java:103)

我不明白为什么会收到此异常。我试图增加 JVM 内存然后我也得到了这个异常。

基准代码如下。

package com.code4refernce.caliper;
import java.util.Random;
import java.util.regex.Pattern;

import com.google.caliper.Param;
import com.google.caliper.SimpleBenchmark;

public class SimpleCaliperTest extends SimpleBenchmark {
    String regex = "(\\d{3}-\\d{3}-\\d{4})|(\\d{10})";
    Pattern REGEX_PATTERN = Pattern.compile(regex);

    String mdn[];
    Random random;
    @Param
    int index;

    @Override 
    protected void setUp() {
         random = new Random(0);
        mdn = new String[4];
            mdn[0] = "098412sdfasdf8000";
            mdn[1] = "11345";
            mdn[2] = "1423567890";
            mdn[3] = "123-456-7890";
    }


    public Boolean[] timeStringLen(int reps){
        Boolean results[] = new Boolean[reps];

        for(int i = 0; i<reps; i ++){

            results [i]= mdnCheckRegularMethod(mdn[index]);
        }
        return results;
    }
    public Boolean[] timeRegex(int reps){
        Boolean results[] = new Boolean[reps];
        for(int i = 0; i<reps; i ++){

            results[i]=mdnCheckRegEx(mdn[index]);
        }
        return results;
    }
    private boolean mdnCheckRegularMethod(String mdn){
        boolean result = false;

        if(mdn.length()==10){
            try{
                Integer.parseInt(mdn);
                result = true;
            }catch(Exception e){
                result = false;
            }
        }
        else if(mdn.length() == 13){
            byte[] bmdn = mdn.getBytes();
            for(int i = 0; i<bmdn.length; i++){
                if((i == 3 || i == 6) && bmdn[i] == '-'){}
                else if(bmdn[i] >= '0' && bmdn[i]<='9'){}
                else{
                    result = false;
                    break;
                }
            }
        }
        else{
            result = false;
        }
        return result;
    }

    private boolean mdnCheckRegEx(String mdn){
        return REGEX_PATTERN.matcher(mdn).matches();
    }
}

以及运行 caliper 基准测试的主类。

package com.code4refernce.caliper;
import com.google.caliper.Runner;

    public class CaliperRunner {
        public static void main(String[] args) {
            String myargs[] = new String[2];
            myargs[0] = new String("-Dindex=0,1,2,3");
            myargs[1] = new String("-Jmemory=-Xms1024m ");
            Runner.main(SimpleCaliperTest.class, myargs);
        }
    }

我不明白这里出了什么问题。谁能指出来?

【问题讨论】:

  • 第24行是哪一个?布尔数组还是对 mdnCheckRegularMethod 的调用?
  • 布尔[] 结果 = 新布尔[reps]; \\line24
  • 如果使用原生的boolean类型进行数组初始化呢?
  • 我试过了,而且成功了。谢谢。但无法得到这种行为背后的原因。
  • Boolean 数组创建了对布尔类型的 reps 空引用的数量(每个引用大约 8 个字节)。而原始替代方案仅分配原始类型所需的空间,请参见例如stackoverflow.com/questions/3733215/…。换句话说,它可能在未来再次失败,因为它取决于reps 的大小。 (我对卡尺不熟悉)。

标签: java jvm caliper


【解决方案1】:

您的方法timeStringLen(int reps) 可以使用reps 调用,最高可达Integer.MAX_VALUE。您可以通过-Xmx 开关为您的 VM 提供更多内存,但您最好不要分配不必要的大数组,因为它根本不需要:

public boolean timeStringLen(int reps){
    boolean result = false;

    for(int i = 0; i<reps; i ++){
        result ^= mdnCheckRegularMethod(mdn[index]);
    }
    return result;
}

这做同样的工作,返回值的唯一原因是防止 JIT 将其全部优化掉。这里异或就够了,计算方法返回 true 的情况是另一种可能。


但是您的基准测试很可能还有另一个问题:使用的reps 的高值表明它的运行速度比我预期的要快。每次迭代的结果似乎都是一样的,我猜你的循环被优化为类似

result[i] = Boolean.TRUE

我认为您不想测量。使用类似的东西

Random random = new Random(0);
mdn = new String[4][1<<16];
for (int i=0; i<mdn.length; ++i) {
    mdn[0][i] = String.format("%03ddsfasdf00000", random.nextInt(1000));
    mdn[1][i] = String.format("%04d", random.nextInt(10000));
    mdn[2][i] = String.format("%10d", random.nextInt((int) 1e10));
    mdn[3][i] = String.format("%03d-%03d-%03d", random.nextInt(1000), random.nextInt(1000), random.nextInt(1000));
}

会有帮助的。

【讨论】:

  • 感谢您的回答。我编辑了代码(查看此线程中的第一篇文章)。我不知道为什么正则表达式表现不佳。这里有什么问题吗?
  • @Rakesh 您最好创建一个新问题,因为原始问题已得到解答。标题已经不匹配了。我会将文本复制到一个新问题中并在此处回滚更改。
猜你喜欢
  • 1970-01-01
  • 2012-02-13
  • 2013-05-24
  • 1970-01-01
  • 2012-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多