Анализ производительности try...catch... с точки зрения JVM

задняя часть JVM

Влияет ли try..catch.. на производительность в конце концов?

Эксперимент 1: простое понимание

Просто напишите простую программу

public class Test {
    public static void main(String[] args) {
        int a = 0,b=2;
        try {
            a = b/0;
        }catch (Exception e){
            a = 1;
        }
    }
}

Взгляните на процесс инструкции байт-кода:

 public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=4, args_size=1
         0: iconst_0        push 0
         1: istore_1        pop并保存到局部变量1
         2: iconst_2       push 2
         3: istore_2       pop并保存到局部变量2
         4: iload_2        从局部变量里拿出并push
         5: iconst_0        push 0 
         6: idiv          栈顶两数相除
         7: istore_1
         8: goto          14
        11: astore_3
        12: iconst_1
        13: istore_1
        14: return
      Exception table:
         from    to  target type
             4     8    11   Class java/lang/Exception
      LineNumberTable:
        line 8: 0
        line 10: 4
        line 13: 8
        line 11: 11
        line 12: 12
        line 14: 14
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
           12       2     3     e   Ljava/lang/Exception;
            0      15     0  args   [Ljava/lang/String;
            2      13     1     a   I
            4      11     2     b   I
      StackMapTable: number_of_entries = 2
        frame_type = 255 /* full_frame */
          offset_delta = 11
          locals = [ class "[Ljava/lang/String;", int, int ]
          stack = [ class java/lang/Exception ]
        frame_type = 2 /* same */
}

Вы можете видеть, что есть таблица исключений:

      Exception table:
         from    to  target type
             4     8    11   Class java/lang/Exception

fromвыражатьtry catchначальный адресtoвыражатьtry catchконечный адресtargetУказывает начальный бит обработки исключенияtypeУказывает имя класса исключений

Когда во время работы кода возникает ошибка, он сначала определяет, находится ли место ошибки вfrom - toдиапазон, если да, то отtargetБит флага выполняется вниз, если нет ошибки, напрямуюgotoприбытьreturn. Видно, что если код не ошибается, производительность почти не меняется, и она такая же, как при обычном выполнении кода.

Какова концепция времени обработки исключений?

Эксперимент 2: длительный тест обработки исключений

public class Test {
    public static void main(String[] args) {
        int a = 0,b=2;
        long startTime = System.nanoTime();
        for (int i = 10; i>0;i--){
            try {
                a = b/i;
            }catch (Exception e){
                a = 1;
            }finally {

            }
        }
        long runTime = System.nanoTime()-startTime;
        System.out.println(runTime);
    }
}

мне просто нужно поставитьi>0изменить наi>=0, программа выполнит обработку исключения, потому что делитель не может быть равен 0.

Прежде чем я изменил его (запуск без исключения), результат запуска1133После модификации (будет исключение деления на 0) текущий результат44177

Конечно, этот результат связан с вычислительной мощностью процессора, и результаты многократных прогонов почти одинаковы.

Поэтому видно, что когда программа попадает в ловушку, она очень ресурсоемка.

Затем попробуйте поймать снаружи или внутри цикла for, что лучше?

Эксперимент 3: цикл for в попытке

public class Test {
    public static void main(String[] args) {
        int a = 0,b=2;
        long startTime = System.nanoTime();
        try {
            for (int i = 10; i>=0;i--){
                    a = b/i;
            }
        }catch (Exception e){
            a = 1;
        }finally {
            long runTime = System.nanoTime()-startTime;
            System.out.println(runTime);
        }
    }
}

Вывод консоли из нескольких запусков:

46820     48708 54749  47953   46820  45310
  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=5, args_size=1
         0: iconst_0
         1: istore_1
         2: iconst_2
         3: istore_2
         4: bipush        10
         6: istore_3
         7: iload_3
         8: iflt          21
        11: iload_2
        12: iload_3
        13: idiv
        14: istore_1
        15: iinc          3, -1
        18: goto          7
        21: goto          35
        24: astore_3
        25: iconst_1
        26: istore_1
        27: goto          35
        30: astore        4
        32: aload         4
        34: athrow
        35: return
      Exception table:
         from    to  target type
             4    21    24   Class java/lang/Exception
             4    21    30   any
            24    27    30   any
            30    32    30   any

Эксперимент 4: попытка находится вне цикла for

public class Test {
    public static void main(String[] args) {
        int a = 0,b=2;
        long startTime = System.nanoTime();
        for (int i = 10; i>=0;i--){
            try {
                a = b/i;
            }catch (Exception e){
                a = 1;
            }finally {

            }
        }
                long runTime = System.nanoTime()-startTime;
                System.out.println(runTime);
    }
}

Отпечатки консоли:

42289  47953  49463  45688  45310
  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=6, args_size=1
         0: iconst_0
         1: istore_1
         2: iconst_2
         3: istore_2
         4: bipush        10
         6: istore_3
         7: iload_3
         8: iflt          36
        11: iload_2
        12: iload_3
        13: idiv
        14: istore_1
        15: goto          30
        18: astore        4
        20: iconst_1
        21: istore_1
        22: goto          30
        25: astore        5
        27: aload         5
        29: athrow
        30: iinc          3, -1
        33: goto          7
        36: return
      Exception table:
         from    to  target type
            11    15    18   Class java/lang/Exception
            11    15    25   any
            18    22    25   any
            25    27    25   any

Объединив третий и четвертый эксперименты, мы обнаружили, что можно сказать, что производительность обоих одинакова с точки зрения времени выполнения и инструкций байт-кода. Нет ничего страшного в том, что вы считаете, что размещение кода try в цикле for будет излишним и удвоит потребление ресурсов.

Но с точки зрения логики выполнения они немного отличаются.В эксперименте 3, поскольку for находится в try catch, jvm помещает обработку исключений после цикла for при компиляции. который:第24-27行; В эксперименте 4 обработка исключений находится внутри цикла for, а именно:第18-22行. Почти такой же.

Вышеупомянутое является только личной тестовой точкой зрения, если есть какая-либо ошибка, пожалуйста, оставьте сообщение ниже, спасибо!