内存不足错误,Java 堆空间

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20626652/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 03:12:49  来源:igfitidea点击:

out of memory error, java heap space

javaheap-memory

提问by Arief Taufikurrahman

I try to read log file with more than 4 million lines and size more than 400 MB, but I get Out of Memory Error : java heap space. This is my code :

我尝试读取超过 400 万行且大小超过 400 MB 的日志文件,但出现Out of Memory Error : java heap space。这是我的代码:

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);
        }

I tried to increase heap memory to 1GB, but still get that message. What would be the possible cause?

我试图将堆内存增加到 1GB,但仍然收到该消息。可能的原因是什么?

采纳答案by Seelenvirtuose

Ok, you already should have a clue, reading the comments you got.

好的,您应该已经知道了,阅读您收到的评论。

Problem explanation:

问题说明:

Your log file has a size of 400MB. Note, that this is measured in bytes. Now you are reading it line by line with line = bufferedReader.readLine()thus converting some bytes to a string.

您的日志文件大小为 400MB。请注意,这是以字节为单位测量的。现在您正在逐行阅读它,line = bufferedReader.readLine()从而将一些字节转换为字符串。

A Stringinstance in Java internally holds a char[]. But a charin Java takes 2 bytes! So you need at least 800MB of heap space just for storing all the characters. As you are also allocating several other objects, and the JVM itself needs some memory, it is very probable that 1 GB is not enough.

StringJava 中的实例在内部拥有一个char[]. 但是charJava 中的 a 需要 2 个字节!所以你至少需要 800MB 的堆空间来存储所有的字符。由于您还分配了几个其他对象,并且 JVM 本身需要一些内存,因此 1 GB 很可能是不够的。

Additionally, the StringBuffer(by the way: better use StringBuilderfor that) internally uses again a char[], which is expanded (in length) automatically when needed. This expansion is done by doubling the length. So for a 400MB file it has a char[]with a length of 512M. Still remind: A char takes 2 bytes.

此外,StringBuffer(顺便说一句:更好地使用StringBuilder)在内部再次使用 a char[],它在需要时自动扩展(长度)。这种扩展是通过将长度加倍来完成的。因此,对于 400MB 的文件,它char[]的长度为 512M。还是提醒一下:一个char占用2个字节。

So what is the solution? Simply put: Do not read the entire file into memory!

那么解决方法是什么呢?简单地说:不要将整个文件读入内存!

Do that instead:

改为这样做:

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
    }
}

If you need to keep some lines, you should store them in some instance fields of the LogAnalyzer, and/or have this class behave like a state machine.

如果您需要保留一些行,您应该将它们存储在 LogAnalyzer 的某些实例字段中,和/或让此类表现得像一个状态机。