Reputation: 83
I am running a Java program written by another person on more data than the program was initially designed for, e.g. 10-times longer input files, roughly quadratic runtime. I encountered different problems and now aim to solve them bit by bit.
During execution when a lot of output has already been printed (redirected to a file) I get following output:
Exception in thread "main" java.lang.StackOverflowError
at java.io.PrintStream.write(PrintStream.java:480)
[...]
at java.io.PrintStream.write(PrintStream.java:480)
The stack trace is the first thing that confuses me as it is a long repetition of just the same line again and again. Furthermore, it gives no intention where in the code or the execution the problem occurred.
My thoughts / research
PrintStream
only code fragments after searching for "PrintStream"
// reset output stream to suppress the annoying output of the Apache batik library. Gets reset after lib call.
OutputStream tmp=System.out;
System.setOut(new PrintStream(new org.apache.commons.io.output.NullOutputStream()));
drawRes.g2d.stream(new FileWriter(svgFilePath), false);
System.setOut(new PrintStream(tmp));
Call for advice
If you have any advice on what is going one, what the Java code specifically does, please help me understand it. Especially the stack trace frustrates me as it provides no place to begin the fixing. I am also thankful for a general approach on how to tackle this problem, get a stack trace, fix the code to avoid StackOverflow, etc.
Some system environment facts
Java
openjdk version "1.8.0_121"
OpenJDK Runtime Environment (IcedTea 3.3.0) (suse-28.1-x86_64)
OpenJDK 64-Bit Server VM (build 25.121-b13, mixed mode)
Please ask if you need more information!
Notes
Thanks all for your replies!
Upvotes: 8
Views: 1418
Reputation: 21510
These two lines look suspicious:
OutputStream tmp=System.out;
//...
System.setOut(new PrintStream(tmp));
System.out
is already a PrintStream
, so IMHO the lines should read
PrintStream tmp=System.out;
//...
System.setOut(tmp);
What happens otherwise is that you have a near endless wrapping of PrintStream
s within PrintStream
s. The nesting of PrintStreams is only limited through Java heap space - but the call level nesting is much lower.
To verify the hypothesis I created a small test program that first wraps System.out
20 times and prints a stacktrace to verify the call chain. After that it wraps System.out
10_000 times and produces a StackOverflowException.
import java.io.OutputStream;
import java.io.PrintStream;
public class CheckPrintStream {
public static void main(String[] args) {
PrintStream originalSystemOut = System.out;
System.setOut(new PrintStream(System.out) {
@Override
public void write(byte buf[], int off, int len) {
originalSystemOut.write(buf, off, len);
if (len > 2) {
new RuntimeException("Testing PrintStream nesting").printStackTrace(originalSystemOut);
}
}
});
for (int i = 0; i < 20; i++) {
wrapSystemOut();
}
System.out.println("Hello World!");
for (int i = 20; i < 10_000; i++) {
wrapSystemOut();
}
System.out.println("crash!");
}
private static void wrapSystemOut() {
OutputStream tmp = System.out;
System.setOut(new PrintStream(System.out));
}
}
A nesting of around 6000 to 7000 PrintWriters is sufficient to produce a stack overflow.
Upvotes: 8