java - Java读取大文件时如何避免OutOfMemory异常

标签 java java-io large-files objectinputstream bufferedinputstream

我正在开发从文件中读取大量数据的应用程序。基本上,我有一个巨大的文件(大约 1.5 - 2 gig),其中包含不同的对象(每个文件大约有 5 到 1000 万个对象)。我需要阅读所有内容并将它们放入应用程序中的不同 map 中。问题是应用程序在某些时候读取对象时内存不足。仅当我将其设置为使用 -Xmx4096m 时 - 它可以处理该文件。但如果文件更大,它就无法再这样做了。

这是代码片段:

String sampleFileName = "sample.file";
FileInputStream fileInputStream = null;
ObjectInputStream objectInputStream = null;
try{
    fileInputStream = new FileInputStream(new File(sampleFileName));
    int bufferSize = 16 * 1024;
    objectInputStream = new ObjectInputStream(new BufferedInputStream(fileInputStream, bufferSize));
        while (true){
            try{
                Object objectToRead = objectInputStream.readUnshared();
                if (objectToRead == null){
                    break;
                }
                // doing something with the object
            }catch (EOFException eofe){
                eofe.printStackTrace();
                break;
            } catch (Exception e) {
                e.printStackTrace();
                continue;
            }
        }
} catch (Exception e){
        e.printStackTrace();
}finally{
    if (objectInputStream != null){
        try{
            objectInputStream.close();
        }catch (Exception e2){
            e2.printStackTrace();
        }
    }
    if (fileInputStream != null){
        try{
            fileInputStream.close();
        }catch (Exception e2){
            e2.printStackTrace();
        }
    }
}

首先,我使用objectInputStream.readObject()而不是objectInputStream.readUnshared(),所以它部分解决了问题。当我将内存从 2048 增加到 4096 时,它开始解析文件。 BufferedInputStream 已在使用中。从网上我只找到了如何读取行或字节的示例,但没有找到有关对象、性能方面的信息。

如何在不增加JVM内存并避免OutOfMemory异常的情况下读取文件?有没有办法从文件中读取对象,而不在内存中保留其他任何内容?

最佳答案

当读取大文件、解析对象并将它们保存在内存中时,有几种解决方案需要权衡:

  1. 您可以将所有解析的对象放入部署在一台服务器上的应用程序的内存中。它要么需要以非常压缩的方式存储所有对象,例如使用字节或整数来存储 2 个数字或在其他数据结构中进行某种移位。换句话说,将所有对象安装在可能的最小空间中。或者增加该服务器的内存(垂直扩展)

    a) 但是,读取文件可能会占用太多内存,因此您必须分块读取它们。例如,这就是我对 json 文件所做的事情:

    JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8"));
        if (reader.hasNext()) {
            reader.beginObject();
            String name = reader.nextName();
    
            if ("content".equals(name)) {
                reader.beginArray();
    
                parseContentJsonArray(reader, name2ContentMap);
    
                reader.endArray();
            }
            name = reader.nextName();
            if ("ad".equals(name)) {
                reader.beginArray();
    
                parsePrerollJsonArray(reader, prerollMap);
    
                reader.endArray();
            }
        }
    

    这个想法是有一种方法来识别某个对象何时开始和结束,并只读取该部分。

    b) 如果可以的话,您还可以在源头将文件拆分为较小的文件,这样会更容易阅读。

  2. 您无法在一台服务器上容纳该应用程序的所有解析对象。在这种情况下,您必须根据某些对象属性进行分片。例如,根据美国州将数据拆分到多个服务器。

希望它对您的解决方案有所帮助。

关于java - Java读取大文件时如何避免OutOfMemory异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45919083/

相关文章:

python - 合并多个csv文件与python中不同列的错误与writerow

java - 如何将邮件从 gmail 路由到 mailgun?

java - CORBA::使用 IIOP 获取客户端 ORB 地址和端口

java - JOGL 小程序与 WebGL

java - JDBC 连接池内存问题(Java EE 应用程序)

java - 系统找不到指定的文件,但文件存在

java - 将文件读入二维数组

xml - 执行 Storm 启动器时出错

python - Pandas HDFStore 用于核外顺序读/写可变大小的集合

c# - 在 .NET 中如何最好地使用 XPath 处理非常大的 XML 文件?