简体   繁体   中英

StackOverflowError when trying to print a stacktrace

I got the following stacktrace when trying to print a stacktrace to the console:

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)
...

Has anyone seen something like this before? What could have caused this? (Unfortunately I received the stacktrace from a user, so I can't say whether the JVM configuration was changed in any way.)

The method call that caused this was a simple catch-and-print, like this:

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

Although I can't publish any more code, I can guarantee that the IOException was thrown by the getCanonicalFile call, because that's the only call within the try-clause that can throw an IOException.

If you initialise two Throwable s to be mutual causes of one another, you'll get a StackOverflowError if you attempt to print the stacktrace of one of them.

The following class demonstrates this behaviour:

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

We need two Throwable s in this example because it's not possible to set a Throwable to be its own cause. If you try to do this, you'll get an IllegalArgumentException .

Alternatively, you can also get a stack-overflow error if you have a ridiculously long chain of cause exceptions. On my machine at least (Kubuntu Natty, x64, OpenJDK 1.6), I found that a chain of 8000 cause exceptions is enough to generate a StackOverflowError , as the following class demonstrates:

public class StackTraceStackOverflow2 {
    public static void main(String[] args) {
        Error e = null;
        for (int i = 0; i < 8000; ++i) {
            e = new Error(null, e);
        }

        e.printStackTrace(System.out);
    }
}

You may have to adjust the number 8000 on other systems.

Note that I used the two-argument Error constructor in this second example. If I used the constructor that takes a single Throwable parameter, the exception message is populated using the cause exception. This message gets longer and longer as the chain of exceptions grows, and as a result you are more likely to end up with an OutOfMemoryError than a StackOverflowError .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM