예외를 던질 때 어느 부분이 비쌉니까?


256

Java에서 실제로 오류가 없을 때 throw / catch를 논리의 일부로 사용하는 것은 예외를 던지고 잡는 것이 비싸고 루프에서 여러 번 수행하는 것이 일반적으로 다른 것보다 훨씬 느리기 때문에 일반적으로 나쁜 생각입니다 (일부) 예외를 던지지 않는 제어 구조.

내 질문은 던지기 / 캐치 자체에서 발생하거나 Exception 객체를 만들 때 발생하는 비용입니까 (실행 스택을 포함하여 많은 런타임 정보를 얻으므로)?

다른 말로하면

Exception e = new Exception();

그러나 던지지 마십시오. 던지기 비용의 대부분입니까, 아니면 던지기 + 잡기가 비싼 것을 처리합니까?

try / catch 블록에 코드를 넣는 것이 해당 코드를 실행하는 비용에 추가되는지 묻지 않고 예외를 잡는 것이 비싼 부분인지 또는 예외를 만드는 (생성자를 호출하는 것) 비싼 부분인지를 묻습니다 .

이것을 요청하는 또 다른 방법은 예외 인스턴스 하나를 만들어 던졌다가 다시 잡는 경우 던질 때마다 새 예외를 만드는 것보다 훨씬 빠릅니다.


20
스택 추적을 채우고 채우고 있다고 생각합니다.
Elliott Frisch

12
이것을 확인하십시오 : stackoverflow.com/questions/16451777/…
Jorge

"예제 하나의 인스턴스를 만들어서 던졌다가 다시 잡았다면"예외가 만들어 질 때 스택 추적이 채워 져서 던져진 장소에 관계없이 항상 같은 stactrace가됩니다. 스택 트레이스가 중요하지 않은 경우 아이디어를 시도해 볼 수 있지만 경우에 따라 불가능하지 않은 경우 디버깅이 매우 어려워 질 수 있습니다.
Pshemo

2
@Pshemo 실제로 코드 에서이 작업을 수행 할 계획은 아니며 성능에 대해 묻고이 부조리를 차이를 만들 수있는 예로 사용합니다.
Martin Carney

@MartinCarney 마지막 단락에 대한 답변을 추가했습니다. 즉 예외를 캐싱하면 성능이 향상됩니다. 유용한 경우 코드를 추가 할 수 있으며 그렇지 않은 경우 답변을 삭제할 수 있습니다.
Harry

답변:


267

만들기 예외 대상은 다른 일반 객체를 만드는 것보다 더 비싼 없습니다. 주요 비용은 fillInStackTrace호출 스택을 안내하고 스택 추적을 작성하는 데 필요한 모든 정보 (클래스, 메소드 이름, 행 번호 등)를 수집하는 기본 메소드에 숨겨져 있습니다.

높은 예외 비용에 대한 신화는 대부분의 Throwable생성자가 암시 적으로 호출 한다는 사실에서 비롯됩니다 fillInStackTrace. 그러나 스택 추적없이 생성하는 생성자 가 하나 Throwable있습니다. 인스턴스화하기가 매우 빠른 던지기를 만들 수 있습니다. 간단한 예외를 만드는 또 다른 방법은 재정의하는 것 fillInStackTrace입니다.


이제 예외 를 던지는 것은 어떻습니까?
사실, 던져진 예외가되는 위치에 따라 달라 붙 잡았다 .

동일한 메소드에서 (또는 더 정확하게는 컨텍스트가 인라인으로 인해 여러 메소드를 포함 할 수 있기 때문에)보다 정확하게 잡히면 (물론 JIT 컴파일 후) throw빠르고 간단 goto합니다.

그러나 catch블록이 스택의 깊숙한 곳에있는 경우 JVM은 스택 프레임을 풀어야하며, 이는 훨씬 더 오래 걸릴 수 있습니다. synchronized풀리는 것은 제거 된 스택 프레임이 소유 한 모니터를 해제하는 것을 의미하기 때문에 블록이나 방법이 관련된 경우 훨씬 오래 걸립니다 .


적절한 벤치 마크를 통해 위의 내용을 확인할 수는 있지만, 모든 측면이 이미 HotSpot의 성능 엔지니어 Alexey Shipilev : The Extra Performance of Lil 'Exception 게시물에서 완벽하게 다루어 졌기 때문에이를 수행 할 필요는 없습니다 .


8
이 기사에서 언급하고 여기에서 다룬 바와 같이 예외를 던지거나 잡는 데 드는 비용은 호출의 깊이에 크게 의존한다는 것입니다. 여기서 중요한 것은 "예외가 비싸다"는 말이 실제로 정확하지 않다는 것입니다. 더 정확한 진술은 예외 '비용'이 비쌀 수 있다는 것입니다. 솔직히 말해서 "정말 예외적 인 사례"(이 기사에서와 같이)에 대한 예외 만 사용하는 것은 너무 강력하다고 생각합니다. 정상적인 반환 흐름을 벗어나는 거의 모든 것에 완벽하며 실제 응용 프로그램에서 이러한 방식을 사용하면 성능에 미치는 영향을 감지하기가 어렵습니다.
JimmyJames

14
예외의 오버 헤드를 수량화하는 것이 좋습니다. 이 철저한 기사 (실제로 쿼리 된 스택 트레이스로 1000 스택 프레임 깊이로 던지고 동적 예외를 포착하는 것)에서보고 된 최악의 경우에도 80 마이크로 초가 걸립니다. 시스템에서 초당 수천 개의 예외를 처리해야하는 경우에는 중요하지만 걱정할 가치는 없습니다. 그리고 이것이 최악의 경우입니다. 스택 트레이스가 약간 이상하거나 스택 트레이스를 쿼리하지 않으면 초당 거의 백만 건의 예외를 처리 할 수 ​​있습니다.
meriton

13
많은 사람들이 예외가 "비싸다"는 것을 읽었을 때, "무엇보다 비싸다"고 묻지 말고, "프로그램의 비싸다"고 생각하기 때문에 거의 그렇지 않습니다.
meriton

2
여기에 언급되지 않은 부분이 있습니다. 최적화 적용을 막는 데 드는 잠재적 비용. 극단적 인 예는 "머들 링 (muddling)"스택 추적을 피하기 위해 인라인하지 않는 JVM이지만, 예외의 유무가 C ++에서 최적화를 중단하거나 중단시키는 (마이크로) 벤치 마크를 보았습니다.
Matthieu M.

3
@MatthieuM. 예외 및 try / catch 블록으로 인해 JVM이 인라인되지 않습니다. 컴파일 된 메소드의 경우 실제 스택 추적은 메타 데이터로 저장된 가상 스택 프레임 테이블에서 재구성됩니다. try / catch와 호환되지 않는 JIT 최적화를 기억할 수 없습니다. try / catch 구조 자체는 메소드 코드에 아무 것도 추가하지 않으며 코드 외에는 예외 테이블로만 존재합니다.
apangin

72

대부분의 Throwable생성자 에서 첫 번째 작업은 대부분 의 비용이 드는 스택 추적채우는 것 입니다.

그러나 스택 추적을 비활성화하는 플래그가있는 보호 생성자가 있습니다. 이 생성자 는 확장 할 때도 액세스 할 수 Exception있습니다. 사용자 정의 예외 유형을 작성하면 스택 추적 작성을 피하고 적은 정보로도 성능을 향상시킬 수 있습니다.

일반적인 방법으로 모든 유형의 단일 예외를 작성하면 스택 추적을 채우는 오버 헤드없이 여러 번 다시 던질 수 있습니다. 그러나 스택 추적은 특정 인스턴스에서 발생한 위치가 아니라 생성 된 위치를 반영합니다.

현재 버전의 Java는 스택 추적 작성을 최적화하려고 시도합니다. 기본 코드는 스택 추적을 채우기 위해 호출되며, 추적은 더 가벼운 기본 구조로 추적을 기록합니다. 해당 자바 StackTraceElement객체는 느리게 만이 기록에서 만든 getStackTrace(), printStackTrace()추적을 필요로하거나 다른 방법이라고합니다.

스택 트레이스 생성을 제거하면 다른 주요 비용으로 스로우와 캐치 사이에서 스택을 풀 수 있습니다. 예외가 포착되기 전에 발생하는 개입 프레임이 적을수록 더 빠릅니다.

예외적 인 경우에만 예외가 발생하도록 프로그램을 설계하고 이와 같은 최적화는 정당화하기 어렵습니다.



25

여기 예외에 대한 좋은 글이 있습니다.

http://shipilev.net/blog/2014/exceptional-performance/

결론은 스택 트레이스 구성과 스택 풀림이 고가의 부품이라는 것입니다. 아래 코드는 1.7스택 추적을 켜거나 끌 수 있는 기능을 활용 합니다. 그런 다음이를 사용하여 다른 시나리오에 어떤 비용이 드는지 확인할 수 있습니다.

다음은 객체 생성의 타이밍입니다. String여기에 추가 했으므로 스택을 작성하지 않으면 JavaExceptionObject 및 a 생성에 거의 차이가 없음을 알 수 있습니다 String. 스택 쓰기를 설정하면 차이가 극적으로 나타납니다. 즉, 최소 1 배 이상 느립니다.

Time to create million String objects: 41.41 (ms)
Time to create million JavaException objects with    stack: 608.89 (ms)
Time to create million JavaException objects without stack: 43.50 (ms)

다음은 특정 깊이에서 백만 번 던지기까지 얼마나 오래 걸 렸는지 보여줍니다.

|Depth| WriteStack(ms)| !WriteStack(ms)| Diff(%)|
|   16|           1428|             243| 588 (%)|
|   15|           1763|             393| 449 (%)|
|   14|           1746|             390| 448 (%)|
|   13|           1703|             384| 443 (%)|
|   12|           1697|             391| 434 (%)|
|   11|           1707|             410| 416 (%)|
|   10|           1226|             197| 622 (%)|
|    9|           1242|             206| 603 (%)|
|    8|           1251|             207| 604 (%)|
|    7|           1213|             208| 583 (%)|
|    6|           1164|             206| 565 (%)|
|    5|           1134|             205| 553 (%)|
|    4|           1106|             203| 545 (%)|
|    3|           1043|             192| 543 (%)| 

다음은 거의 확실하게 단순화 된 것입니다 ...

스택 쓰기를 사용하여 16의 깊이를 취하면 객체 생성에 약 ~ 40 %의 시간이 걸리며 실제 스택 추적은이 중 대부분을 차지합니다. JavaException 객체 인스턴스화의 ~ 93 %는 스택 추적이 발생하기 때문입니다. 이것은이 경우 스택을 푸는 데 다른 시간의 50 %가 걸린다는 것을 의미합니다.

스택 추적을 끄면 객체 생성이 훨씬 작은 비율, 즉 20 %를 차지하고 스택 해제가 시간의 80 %를 차지합니다.

두 경우 모두 스택 해제는 전체 시간의 큰 부분을 차지합니다.

public class JavaException extends Exception {
  JavaException(String reason, int mode) {
    super(reason, null, false, false);
  }
  JavaException(String reason) {
    super(reason);
  }

  public static void main(String[] args) {
    int iterations = 1000000;
    long create_time_with    = 0;
    long create_time_without = 0;
    long create_string = 0;
    for (int i = 0; i < iterations; i++) {
      long start = System.nanoTime();
      JavaException jex = new JavaException("testing");
      long stop  =  System.nanoTime();
      create_time_with += stop - start;

      start = System.nanoTime();
      JavaException jex2 = new JavaException("testing", 1);
      stop = System.nanoTime();
      create_time_without += stop - start;

      start = System.nanoTime();
      String str = new String("testing");
      stop = System.nanoTime();
      create_string += stop - start;

    }
    double interval_with    = ((double)create_time_with)/1000000;
    double interval_without = ((double)create_time_without)/1000000;
    double interval_string  = ((double)create_string)/1000000;

    System.out.printf("Time to create %d String objects: %.2f (ms)\n", iterations, interval_string);
    System.out.printf("Time to create %d JavaException objects with    stack: %.2f (ms)\n", iterations, interval_with);
    System.out.printf("Time to create %d JavaException objects without stack: %.2f (ms)\n", iterations, interval_without);

    JavaException jex = new JavaException("testing");
    int depth = 14;
    int i = depth;
    double[] with_stack    = new double[20];
    double[] without_stack = new double[20];

    for(; i > 0 ; --i) {
      without_stack[i] = jex.timerLoop(i, iterations, 0)/1000000;
      with_stack[i]    = jex.timerLoop(i, iterations, 1)/1000000;
    }
    i = depth;
    System.out.printf("|Depth| WriteStack(ms)| !WriteStack(ms)| Diff(%%)|\n");
    for(; i > 0 ; --i) {
      double ratio = (with_stack[i] / (double) without_stack[i]) * 100;
      System.out.printf("|%5d| %14.0f| %15.0f| %2.0f (%%)| \n", i + 2, with_stack[i] , without_stack[i], ratio);
      //System.out.printf("%d\t%.2f (ms)\n", i, ratio);
    }
  }
 private int thrower(int i, int mode) throws JavaException {
    ExArg.time_start[i] = System.nanoTime();
    if(mode == 0) { throw new JavaException("without stack", 1); }
    throw new JavaException("with stack");
  }
  private int catcher1(int i, int mode) throws JavaException{
    return this.stack_of_calls(i, mode);
  }
  private long timerLoop(int depth, int iterations, int mode) {
    for (int i = 0; i < iterations; i++) {
      try {
        this.catcher1(depth, mode);
      } catch (JavaException e) {
        ExArg.time_accum[depth] += (System.nanoTime() - ExArg.time_start[depth]);
      }
    }
    //long stop = System.nanoTime();
    return ExArg.time_accum[depth];
  }

  private int bad_method14(int i, int mode) throws JavaException  {
    if(i > 0) { this.thrower(i, mode); }
    return i;
  }
  private int bad_method13(int i, int mode) throws JavaException  {
    if(i == 13) { this.thrower(i, mode); }
    return bad_method14(i,mode);
  }
  private int bad_method12(int i, int mode) throws JavaException{
    if(i == 12) { this.thrower(i, mode); }
    return bad_method13(i,mode);
  }
  private int bad_method11(int i, int mode) throws JavaException{
    if(i == 11) { this.thrower(i, mode); }
    return bad_method12(i,mode);
  }
  private int bad_method10(int i, int mode) throws JavaException{
    if(i == 10) { this.thrower(i, mode); }
    return bad_method11(i,mode);
  }
  private int bad_method9(int i, int mode) throws JavaException{
    if(i == 9) { this.thrower(i, mode); }
    return bad_method10(i,mode);
  }
  private int bad_method8(int i, int mode) throws JavaException{
    if(i == 8) { this.thrower(i, mode); }
    return bad_method9(i,mode);
  }
  private int bad_method7(int i, int mode) throws JavaException{
    if(i == 7) { this.thrower(i, mode); }
    return bad_method8(i,mode);
  }
  private int bad_method6(int i, int mode) throws JavaException{
    if(i == 6) { this.thrower(i, mode); }
    return bad_method7(i,mode);
  }
  private int bad_method5(int i, int mode) throws JavaException{
    if(i == 5) { this.thrower(i, mode); }
    return bad_method6(i,mode);
  }
  private int bad_method4(int i, int mode) throws JavaException{
    if(i == 4) { this.thrower(i, mode); }
    return bad_method5(i,mode);
  }
  protected int bad_method3(int i, int mode) throws JavaException{
    if(i == 3) { this.thrower(i, mode); }
    return bad_method4(i,mode);
  }
  private int bad_method2(int i, int mode) throws JavaException{
    if(i == 2) { this.thrower(i, mode); }
    return bad_method3(i,mode);
  }
  private int bad_method1(int i, int mode) throws JavaException{
    if(i == 1) { this.thrower(i, mode); }
    return bad_method2(i,mode);
  }
  private int stack_of_calls(int i, int mode) throws JavaException{
    if(i == 0) { this.thrower(i, mode); }
    return bad_method1(i,mode);
  }
}

class ExArg {
  public static long[] time_start;
  public static long[] time_accum;
  static {
     time_start = new long[20];
     time_accum = new long[20];
  };
}

이 예제의 스택 프레임은 일반적으로 찾은 것보다 작습니다.

javap를 사용하여 바이트 코드를 엿볼 수 있습니다

javap -c -v -constants JavaException.class

즉, 이것은 방법 4에 대한 것입니다 ...

   protected int bad_method3(int, int) throws JavaException;
flags: ACC_PROTECTED
Code:
  stack=3, locals=3, args_size=3
     0: iload_1       
     1: iconst_3      
     2: if_icmpne     12
     5: aload_0       
     6: iload_1       
     7: iload_2       
     8: invokespecial #6                  // Method thrower:(II)I
    11: pop           
    12: aload_0       
    13: iload_1       
    14: iload_2       
    15: invokespecial #17                 // Method bad_method4:(II)I
    18: ireturn       
  LineNumberTable:
    line 63: 0
    line 64: 12
  StackMapTable: number_of_entries = 1
       frame_type = 12 /* same */

Exceptions:
  throws JavaException

13

스택 추적으로 Exceptionwith를 만들 null려면 throwtry-catch블록을 만드는 데 시간이 걸립니다 . 그러나 스택 추적을 채우는 데 평균 5 배가 더 걸립니다 .

성능에 미치는 영향을 보여주기 위해 다음 벤치 마크를 만들었습니다. -Djava.compiler=NONE컴파일러 최적화를 비활성화하기 위해 Run Configuration에 추가했습니다 . 스택 추적 작성의 영향을 측정 Exception하기 위해 스택없는 생성자를 활용 하도록 클래스를 확장했습니다 .

class NoStackException extends Exception{
    public NoStackException() {
        super("",null,false,false);
    }
}

벤치 마크 코드는 다음과 같습니다.

public class ExceptionBenchmark {

    private static final int NUM_TRIES = 100000;

    public static void main(String[] args) {

        long throwCatchTime = 0, newExceptionTime = 0, newObjectTime = 0, noStackExceptionTime = 0;

        for (int i = 0; i < 30; i++) {
            throwCatchTime += throwCatchLoop();
            newExceptionTime += newExceptionLoop();
            newObjectTime += newObjectLoop();
            noStackExceptionTime += newNoStackExceptionLoop();
        }

        System.out.println("throwCatchTime = " + throwCatchTime / 30);
        System.out.println("newExceptionTime = " + newExceptionTime / 30);
        System.out.println("newStringTime = " + newObjectTime / 30);
        System.out.println("noStackExceptionTime = " + noStackExceptionTime / 30);

    }

    private static long throwCatchLoop() {
        Exception ex = new Exception(); //Instantiated here
        long start = System.currentTimeMillis();
        for (int i = 0; i < NUM_TRIES; i++) {
            try {
                throw ex; //repeatedly thrown
            } catch (Exception e) {

                // do nothing
            }
        }
        long stop = System.currentTimeMillis();
        return stop - start;
    }

    private static long newExceptionLoop() {
        long start = System.currentTimeMillis();
        for (int i = 0; i < NUM_TRIES; i++) {
            Exception e = new Exception();
        }
        long stop = System.currentTimeMillis();
        return stop - start;
    }

    private static long newObjectLoop() {
        long start = System.currentTimeMillis();
        for (int i = 0; i < NUM_TRIES; i++) {
            Object o = new Object();
        }
        long stop = System.currentTimeMillis();
        return stop - start;
    }

    private static long newNoStackExceptionLoop() {
        long start = System.currentTimeMillis();
        for (int i = 0; i < NUM_TRIES; i++) {
            NoStackException e = new NoStackException();
        }
        long stop = System.currentTimeMillis();
        return stop - start;
    }

}

산출:

throwCatchTime = 19
newExceptionTime = 77
newObjectTime = 3
noStackExceptionTime = 15

이것은 a를 만드는 것이 NoStackException같은 것을 반복적으로 던지는 것만큼이나 비싸다는 것을 의미합니다 Exception. 또한 Exception스택 추적을 작성하고 채우는 데 약 4 배 더 오래 걸린다 는 것을 보여줍니다 .


1
시작 시간 전에 하나의 Exception 인스턴스를 만든 다음 루프에서 반복적으로 throw + catch하는 경우를 하나 더 추가 할 수 있습니까? 그것은 단지 던지기 + 잡기의 비용을 보여줄 것입니다.
Martin Carney

@MartinCarney 큰 제안입니다! 나는 그렇게하기 위해 대답을 업데이트했습니다.
Austin D

테스트 코드를 약간 수정했는데 컴파일러가 정확한 숫자를 얻지 못하게하는 최적화를하는 것처럼 보입니다.
Martin Carney

@MartinCarney 할인 컴파일러 최적화에 대한 답변을 업데이트했습니다
Austin D


4

질문의이 부분은 ...

이것을 요청하는 또 다른 방법은 예외 인스턴스 하나를 만들어 던졌다가 다시 잡는 경우 던질 때마다 새 예외를 만드는 것보다 훨씬 빠릅니다.

예외를 생성하고 어딘가에 캐싱하면 성능이 향상되는 것처럼 보입니다. 그렇습니다. 이미 만들어 졌기 때문에 객체 생성시 기록되는 스택을 끄는 것과 같습니다.

이것들은 내가 얻은 타이밍입니다.이 후주의 사항을 읽으십시오 ...

|Depth| WriteStack(ms)| !WriteStack(ms)| Diff(%)|
|   16|            193|             251| 77 (%)| 
|   15|            390|             406| 96 (%)| 
|   14|            394|             401| 98 (%)| 
|   13|            381|             385| 99 (%)| 
|   12|            387|             370| 105 (%)| 
|   11|            368|             376| 98 (%)| 
|   10|            188|             192| 98 (%)| 
|    9|            193|             195| 99 (%)| 
|    8|            200|             188| 106 (%)| 
|    7|            187|             184| 102 (%)| 
|    6|            196|             200| 98 (%)| 
|    5|            197|             193| 102 (%)| 
|    4|            198|             190| 104 (%)| 
|    3|            193|             183| 105 (%)| 

물론 이것의 문제는 스택 추적이 이제 객체가 어디에서 발생했는지가 아니라 인스턴스를 생성했는지를 가리 킵니다.


3

@AustinD의 대답을 출발점으로 사용하여 약간의 조정을했습니다. 하단에 코드.

하나의 Exception 인스턴스가 반복적으로 발생하는 경우를 추가하는 것 외에도 정확한 성능 결과를 얻을 수 있도록 컴파일러 최적화를 해제했습니다. 이 답변-Djava.compiler=NONE 에 따라 VM 인수에 추가 했습니다 . (이클립스에서 Run Configuration → Arguments를 편집 하여이 VM 인수를 설정하십시오)

결과 :

new Exception + throw/catch = 643.5
new Exception only          = 510.7
throw/catch only            = 115.2
new String (benchmark)      = 669.8

따라서 예외를 만드는 것은 던지고 잡는 것보다 약 5 배가 소요됩니다. 컴파일러가 많은 비용을 최적화하지 못한다고 가정합니다.

비교를 위해 최적화를 비활성화하지 않은 동일한 테스트 실행은 다음과 같습니다.

new Exception + throw/catch = 382.6
new Exception only          = 379.5
throw/catch only            = 0.3
new String (benchmark)      = 15.6

암호:

public class ExceptionPerformanceTest {

    private static final int NUM_TRIES = 1000000;

    public static void main(String[] args) {

        double numIterations = 10;

        long exceptionPlusCatchTime = 0, excepTime = 0, strTime = 0, throwTime = 0;

        for (int i = 0; i < numIterations; i++) {
            exceptionPlusCatchTime += exceptionPlusCatchBlock();
            excepTime += createException();
            throwTime += catchBlock();
            strTime += createString();
        }

        System.out.println("new Exception + throw/catch = " + exceptionPlusCatchTime / numIterations);
        System.out.println("new Exception only          = " + excepTime / numIterations);
        System.out.println("throw/catch only            = " + throwTime / numIterations);
        System.out.println("new String (benchmark)      = " + strTime / numIterations);

    }

    private static long exceptionPlusCatchBlock() {
        long start = System.currentTimeMillis();
        for (int i = 0; i < NUM_TRIES; i++) {
            try {
                throw new Exception();
            } catch (Exception e) {
                // do nothing
            }
        }
        long stop = System.currentTimeMillis();
        return stop - start;
    }

    private static long createException() {
        long start = System.currentTimeMillis();
        for (int i = 0; i < NUM_TRIES; i++) {
            Exception e = new Exception();
        }
        long stop = System.currentTimeMillis();
        return stop - start;
    }

    private static long createString() {
        long start = System.currentTimeMillis();
        for (int i = 0; i < NUM_TRIES; i++) {
            Object o = new String("" + i);
        }
        long stop = System.currentTimeMillis();
        return stop - start;
    }

    private static long catchBlock() {
        Exception ex = new Exception(); //Instantiated here
        long start = System.currentTimeMillis();
        for (int i = 0; i < NUM_TRIES; i++) {
            try {
                throw ex; //repeatedly thrown
            } catch (Exception e) {
                // do nothing
            }
        }
        long stop = System.currentTimeMillis();
        return stop - start;
    }
}

최적화 비활성화 = 훌륭한 기술! 다른 사람을 오도하지 않도록 원래의 답변을 편집하겠습니다.
Austin D

3
순수 해석 모드는 실제 성능과 관련이 없으므로 최적화를 비활성화하면 결함이있는 벤치 마크를 작성하는 것보다 낫지 않습니다. JVM의 힘은 JIT 컴파일러이므로 실제 응용 프로그램의 작동 방식을 반영하지 않는 것을 측정하는 요점은 무엇입니까?
apangin

2
이 '벤치 마크'에서 수렴 된 것보다 예외를 만들고 던지고 잡는 데는 훨씬 더 많은 측면이 있습니다. 이 글 을 읽어 보시기를 강력히 권합니다 .
apangin
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.