内存不足错误,java堆空间

时间:2013-12-17 05:32:12

标签: java heap-memory

我尝试读取超过400万行且大小超过400 MB的日志文件,但我得到内存不足错误:java堆空间。这是我的代码:

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

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

1 个答案:

答案 0 :(得分:20)

好的,你已经有了一个线索,阅读你得到的评论。

问题解释:

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

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

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

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

改为:

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

如果需要保留一些行,则应将它们存储在LogAnalyzer的某些实例字段中,和/或使此类的行为类似于状态机。