Java StackOverflowError en java.io.PrintStream.write (PrintStream.java:480) y no hay seguimiento de la pila más

JNWolf:

Estoy corriendo un programa Java escrito por otra persona en más datos que el programa fue diseñado inicialmente para, por ejemplo, 10 veces los archivos de entrada más larga, más o menos tiempo de ejecución cuadrática. Me encontré con diferentes problemas y ahora apunto para resolverlos poco a poco.

Durante la ejecución, cuando ya se ha impreso un montón de salida (redirige a un archivo) consigo siguiente salida:

Exception in thread "main" java.lang.StackOverflowError  
        at java.io.PrintStream.write(PrintStream.java:480)  
        [...]  
        at java.io.PrintStream.write(PrintStream.java:480)

El seguimiento de la pila es la primera cosa que me confunde, ya que es una larga repetición de la misma línea una y otra vez. Además, se da ninguna intención en qué parte del código o la ejecución se produjo el problema.

Mi pensamientos / investigación

  • StackOverflowError
    • también puede indicar menos memoria. Con la bandera -Xmx110G I, siempre y 110 de memoria G y monitoreamos mientras que la ejecución, sólo se utilizaron hasta ~ 32 g. Así que esto no es, probablemente, el problema aquí.
    • puede ser efectuado debido a errores de programación que causa un bucle infinito. Sin embargo, realmente no puedo comprobar esto ya que no soy lo suficientemente familiarizado con el código y el seguimiento de la pila no me ayuda para encontrar la ubicación del problema en el código.
    • [Hipótesis] puede ser causada, porque la escritura de la producción es más lenta que la ejecución y nuevas llamadas de impresión / escritura. Aún así, ¿por qué hay ningún rastro más pila? ¿Cómo podría comprobar y corregir esto?
  • PrintStream

    • sólo fragmentos de código después de la búsqueda de "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));  
      
    • [Hipótesis] la escritura en vacío / nulo no funciona
    • [Solución] omitir si el cambio de flujo de salida y justo "en vivo" con la gran salida creado el Programm parece correr (en otros problemas, pero este es otro caso). Cualquier idea por qué está sucediendo esto?

Convocatoria de consejos
Si usted tiene algún consejo sobre lo que está pasando uno, lo que hace específicamente el código de Java, por favor ayuda a entenderla. Especialmente el seguimiento de la pila me frustra, ya que proporciona no hay lugar para comenzar la fijación. También estoy agradecido por una orientación general sobre cómo hacer frente a este problema, obtener un seguimiento de pila, arreglar el código para evitar Stackoverflow, etc.

Algunos datos de entorno del sistema

  • máquina Linux
  • 128 de memoria 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)
    
  • Por favor, pregunte si necesita más información!

notas

  • Soy bastante nuevo en Java, por lo que estoy agradecido por cada consejo (el programa no está escrito por mí)
  • Este es mi primer post en stackoverflow, me informa por favor donde puedo mejorar mi estilo de hacer y dar formato
  • No soy un hablante nativo de Inglés, así que por favor excusa errores y no dude en preguntar por mí comprensión o correcta

¡Gracias a todos por sus respuestas!

Thomas Solicitante:

Estas dos líneas se ven sospechoso:

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

System.outYa es una PrintStream, así que en mi humilde opinión las líneas deben leer

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

Lo que sucede lo contrario es que tiene una envoltura sin fin próximo de PrintStreams dentro de PrintStreams. El anidamiento de PrintStreams sólo está limitado por el espacio Java heap - pero el nivel de llamada de anidación es mucho menor.


Para verificar la hipótesis de que he creado un pequeño programa de prueba que las primeras envolturas System.out20 veces e imprime un StackTrace para verificar la cadena de llamadas. Después de que envuelve System.out10_000 veces y produce una 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 anidamiento de alrededor de 6.000 a 7.000 PrintWriters es suficiente para producir un desbordamiento de pila.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=137923&siteId=1
Recomendado
Clasificación