StackOverflowError при попытке напечатать трассировку стека - PullRequest
4 голосов
/ 03 декабря 2011

Я получил следующую трассировку стека при попытке вывести ее на консоль:

java.lang.StackOverflowError
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(Unknown Source)
at java.io.BufferedOutputStream.flushBuffer(Unknown Source)
at java.io.BufferedOutputStream.write(Unknown Source)
at java.io.PrintStream.write(Unknown Source)
at sun.nio.cs.StreamEncoder.writeBytes(Unknown Source)
at sun.nio.cs.StreamEncoder.implFlushBuffer(Unknown Source)
at sun.nio.cs.StreamEncoder.flushBuffer(Unknown Source)
at java.io.OutputStreamWriter.flushBuffer(Unknown Source)
at java.io.PrintStream.write(Unknown Source)
at java.io.PrintStream.print(Unknown Source)
at java.io.PrintStream.println(Unknown Source)
at java.lang.Throwable.printStackTrace(Throwable.java:461)
at java.lang.Throwable.printStackTrace(Throwable.java:451)
...

Кто-нибудь видел что-то подобное раньше?Что могло вызвать это?(К сожалению, я получил трассировку стека от пользователя, поэтому я не могу сказать, была ли каким-либо образом изменена конфигурация JVM.)

Вызов метода, который вызвал это, был простым перехватом и печатью, как этот:

try {
  ...
  File canFile = new File(path).getCanonicalFile();
  ...
} catch (IOException e) {
  e.printStackTrace();
}

Хотя я не могу больше публиковать код, я могу гарантировать, что IOException был вызван вызовом getCanonicalFile, потому что это единственный вызов в предложении try, который может вызвать IOException.

1 Ответ

6 голосов
/ 03 декабря 2011

Если вы инициализируете два Throwable s как взаимные причины друг друга, вы получите StackOverflowError, если попытаетесь распечатать трассировку стека одного из них.

Следующий класс демонстрирует этоПоведение:

public class StackTraceStackOverflow {
    public static void main(String[] args) {
        Error e = new Error();
        Error f = new Error(e);
        e.initCause(f);
        e.printStackTrace();
    }
}

Нам нужно два Throwable в этом примере, потому что невозможно установить Throwable в качестве его собственной причины.Если вы попытаетесь это сделать, вы получите IllegalArgumentException.

В качестве альтернативы, вы также можете получить ошибку переполнения стека, если у вас есть смехотворно длинная цепочка исключений причины.По крайней мере, на моей машине (Kubuntu Natty, x64, OpenJDK 1.6) я обнаружил, что для генерирования StackOverflowError достаточно цепочки из 8000 исключительных ситуаций, как демонстрирует следующий класс:необходимо настроить число 8000 в других системах.

Обратите внимание, что я использовал конструктор с двумя аргументами Error во втором примере.Если я использовал конструктор, который принимает один параметр Throwable, сообщение об исключении заполняется с использованием причины исключения.Это сообщение становится все длиннее и длиннее по мере роста цепочки исключений, и в результате вы с большей вероятностью получите OutOfMemoryError, чем StackOverflowError.

...