Pregunta error de memoria, espacio de pila de Java


Intento leer el archivo de registro con más de 4 millones de líneas y un tamaño de más de 400 MB, pero obtengo Out of Memory Error: java espacio de pila. Este es mi código:

File file = new File("C:\\file.log");
        FileReader fileReader = new FileReader(file);
        BufferedReader bufferedReader = new BufferedReader(fileReader);
        StringBuilder stringBuffer = new StringBuilder();
        String line;
        while ((line = bufferedReader.readLine()) != null) {
            stringBuffer.append(line);
        }

Traté de aumentar la memoria del montón a 1GB, pero aún recibo ese mensaje. ¿Cuál sería la causa posible?


5
2017-12-17 05:32


origen


Respuestas:


Ok, ya deberías tener una pista, leyendo los comentarios que recibiste.

Explicación del problema:

Su archivo de registro tiene un tamaño de 400 MB. Tenga en cuenta que esto se mide en bytes. Ahora lo estás leyendo línea por línea con line = bufferedReader.readLine() convirtiendo así algunos bytes en una cadena.

UN String instancia en Java internamente tiene una char[]. Pero una char en Java toma 2 bytes! Por lo tanto, necesita al menos 800 MB de espacio de pila solo para almacenar todos los caracteres. Como también está asignando varios otros objetos, y la JVM necesita algo de memoria, es muy probable que 1 GB no sea suficiente.

Además, el StringBuffer (por cierto: mejor uso StringBuilder para eso) utiliza internamente de nuevo un char[], que se expande (en longitud) automáticamente cuando sea necesario. Esta expansión se realiza duplicando la longitud. Así que para un archivo de 400 MB tiene una char[] Con una longitud de 512M. Todavía recuerde: un char toma 2 bytes.

¿Entonces, cuál es la solución? En pocas palabras: ¡No lea todo el archivo en la memoria!

Hazlo en cambio

class LogAnalyzer {
    private final File logFile;

    LogAnalyzer(File logFile) {
        this.logFile = logFile;
    }

    void analyze() throws IOException {
        try(FileReader fileReader = new FileReader(logFile)) {
            try(BufferedReader bufferedReader = new BufferedReader(fileReader)) {
                String line;
                while ((line = bufferedReader.readLine()) != null) {
                    analyzeLine(line);
                }
            }
        }
    }

    private void analyzeLine(String line) {
        // do whatever you need here
    }
}

Si necesita conservar algunas líneas, debe almacenarlas en algunos campos de instancia del LogAnalyzer, y / o hacer que esta clase se comporte como una máquina de estado.


16
2017-12-17 08:27