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

时间:2018-10-22 14:03:17

标签: java stack-overflow stack-trace outputstream

我正在运行由另一个人编写的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)

堆栈跟踪是使我困惑的第一件事,因为它是一次又一次重复同一行的长时间重复。此外,它也不打算在代码或执行中的哪里出现问题。

我的想法/研究

  • 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));  
      
    • [假设]对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)
    
  • 请询问您是否需要更多信息!

注释

  • 我对Java还是很陌生,所以我很感谢每一个建议(程序不是我写的)
  • 这是我关于stackoverflow的第一篇文章,请告诉我在哪里可以改善询问和格式化的风格
  • 我不是英语母语人士,所以请原谅我的错误,并随时要求理解或纠正我。

感谢您的答复!

1 个答案:

答案 0 :(得分:7)

这两行看起来很可疑:

OutputStream tmp=System.out;
//...
System.setOut(new PrintStream(tmp));

System.out已经是PrintStream,所以恕我直言,这些行应显示为

PrintStream tmp=System.out;
//...
System.setOut(tmp);

否则将发生PrintStreamPrintStream s几乎无休止的包裹。 PrintStream的嵌套仅受Java堆空间限制-但调用级别的嵌套要低​​得多。


为验证该假设,我创建了一个小型测试程序,该程序首先包装System.out 20次,并打印堆栈跟踪以验证调用链。之后,它包装System.out 10_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));
    }
}

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