1

我正在研究从文件读取大量数据的应用程序。基本上,我有一个巨大的文件(大约1.5 - 2演出)包含不同的对象(约5至10百万它们每个文件)。我需要阅读所有这些文件,并将它们放到应用程序中的不同地图上。问题是应用程序在某些时候读取对象时内存不足。只有当我将它设置为使用-Xmx4096m时,它才能处理文件。但是,如果文件会更大,它将无法再做到这一点。如何在读取Java中的大文件时避免OutOfMemory异常

下面的代码片段:

所有的
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异常?有没有办法从文件中读取对象,而不是在内存中保留其他任何东西?

+3

这是简单的物理:更大的文件将需要更多的内存。那里没有魔法。您的文件不包含对象 - 它们包含映射到映射到对象的字符串的字节。 – duffymo

+0

如果您可以在读取主文件时对数据进行排序,则可以使用BufferReader按行读取文件,然后使用PrintWriter将数据追加到已存在的文件或创建新文件。 – Jure

+0

如果文件太大,别无选择,只能将它们存储在F.S.中。阅读:https://commons.apache.org/proper/commons-jcs/ –

回答

1

当读取大文件,分析对象,并让他们在内存中有几种解决方案与多家权衡:

  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. 您无法在一台服务器上安装该应用的所有解析对象。在这种情况下,您必须基于某些对象属性进行分片。例如,将基于US状态的数据拆分为多个服务器。

希望它有助于您的解决方案。

+0

将源文件拆分成更小的文件对我来说是最有帮助的。谢谢! – Kakofonn

相关问题