Исключения без стек трейса в Java

Бывает, видишь в логе исключение, а стек трейса у него нет (он пустой):

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException

Одна строка и всё.

Это происходит, когда программа кидает очень много таких исключений. Сначала они генерируются как надо, с заполненным стек трейсом, и полностью попадают в лог. Потом виртуальная машина решает, что раз такие ошибки происходят очень часто, имеет смысл оптимизировать генерацию этих исключений (см. JIT). Тогда-то у них и пропадает стек трейс.

Поэтому когда вы у себя такое видите и не можете понять, откуда эти исключения вылетают, имеет смысл промотать лог назад (очень далеко назад, как правило) и поискать в том месте, где они впервые появились. И/или можно выключить эту оптимизацию с помощью следующего аргумента JVM

-XX:-OmitStackTraceInFastThrow

Если интересно, можно сымитировать подобную ситуацию простой программой:

public class Main2 {
 public static void main(String... args) {
  for (int i = 0; i < 1000000; i++) {
   try {
    int x = 0 / 0;
   } catch (Exception e) {
    if (e.getStackTrace().length == 0) {
     System.out.println("i=" + i);
     throw e;
    }
   }
  }
 }
}

У меня, например, цикл заканчивается на 12288-й итерации.

Мне не совсем понятна философия этой оптимизации. Да, исключения действительно “тяжёлые”. Но на то они и исключения, что должны происходить редко. И если в вашей программе они выкидываются очень часто, вы явно что-то делаете не так, и плохая производительность — это не главная ваша проблема. Ваша проблема в том, что вы не читали Item 57: Use exceptions only for exceptional conditions из Effective Java Блоха.

Может быть, кто-нибудь из читателей может объяснить?

2 thoughts on “Исключения без стек трейса в Java

Leave a Reply

Your email address will not be published. Required fields are marked *