java.io.PrintStream.write(PrintStream.java:480)中的Java StackOverflowError并且没有进一步的堆栈跟踪

JNW*_*olf 8 java stack-overflow outputstream stack-trace

我正在运行一个由另一个人编写的Java程序,该程序的数据比最初为该程序设计的数据多,例如输入文件的10倍,大致是二次运行时.我遇到了不同的问题,现在的目的是一点一点地解决它们,并感谢我能得到的所有帮助 - 非常感谢您的建议!

在执行期间,当已经打印了大量输出(重定向到文件)时,我得到以下输出:

Exception in thread "main" java.lang.StackOverflowError  
        at java.io.PrintStream.write(PrintStream.java:480)  
        [...]  
        at java.io.PrintStream.write(PrintStream.java:480)
Run Code Online (Sandbox Code Playgroud)

堆栈跟踪是第一件令我困惑的事情,因为它是一次又一次地重复同一条线.此外,它无意在代码或执行中出现问题.

我的想法/研究

  • 的StackOverflowError
    • 可能表示内存太少.使用-Xmx110G标志,我提供了110 G内存并在执行时对其进行监控,仅使用了大约32 G.所以这可能不是问题所在.
    • 由于编程错误导致无限循环,可能会抛出.但是,我真的无法检查这个,因为我对代码不够熟悉,堆栈跟踪无法帮助我在代码中找到问题的位置.
    • [假设]可能是由于输出的写入比执行和新的打印/写入调用慢.不过,为什么没有进一步的堆栈跟踪?我该怎么检查并解决这个问题?
  • 为PrintStream

    • 搜索"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));  
      
      Run Code Online (Sandbox Code Playgroud)
    • [假设]写入void/null不起作用
    • [解决方法]如果跳过输出流的更改并且只是"生效"并且创建了大输出,则程序似乎运行(进入其他问题,但这是另一种情况).任何想法为什么会这样?

征求意见
如果您对正在进行的工作有什么建议,那么Java代码具体做什么,请帮助我理解它.特别是堆栈跟踪让我感到沮丧,因为它没有提供开始修复的地方.我也很感谢有关如何解决此问题,获取堆栈跟踪,修复代码以避免StackOverflow等的一般方法.

一些系统环境事实

  • Linux机器
  • 128 G内存
  • 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)
    
    Run Code Online (Sandbox Code Playgroud)
  • 请询问您是否需要更多信息!

笔记

  • 我对Java很陌生,所以我很感激每一条建议(该程序不是由我编写的)
  • 这是我在stackoverflow上的第一篇文章,请告诉我哪里可以改进我的问询和格式化风格
  • 我不是英语母语人士,所以请原谅错误,随时请求理解或纠正我

谢谢大家的回复!

Tho*_*ger 8

这两行看起来很可疑:

OutputStream tmp=System.out;
//...
System.setOut(new PrintStream(tmp));
Run Code Online (Sandbox Code Playgroud)

System.out已经是一个PrintStream,所以恕我直言应该阅读

PrintStream tmp=System.out;
//...
System.setOut(tmp);
Run Code Online (Sandbox Code Playgroud)

否则会发生在PrintStreams内有无穷无尽的s 包裹PrintStream.PrintStreams的嵌套仅限于Java堆空间 - 但调用级嵌套要低得多.


为了验证这个假设,我创建了一个小测试程序,它首先包装了System.out20次并打印了一个堆栈跟踪来验证调用链.之后它会包装System.out10_000次并产生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));
    }
}
Run Code Online (Sandbox Code Playgroud)

嵌套大约6000到7000个PrintWriters就足以产生堆栈溢出.