1

Je travaille sur l'application qui lit de grandes quantités de données à partir d'un fichier. Fondamentalement, j'ai un énorme fichier (environ 1,5 - 2 concerts) contenant des objets différents (~ 5 à 10 millions d'entre eux par fichier). Je dois tous les lire et les mettre à différentes cartes dans l'application. Le problème est que l'application manque de mémoire lors de la lecture des objets à un moment donné. Ce n'est que lorsque je le mets à utiliser -Xmx4096m - qu'il peut gérer le fichier. Mais si le fichier est plus grand, il ne pourra plus le faire.Comment éviter l'exception OutOfMemory lors de la lecture de fichiers volumineux en Java

est ici l'extrait de code:

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

Tout d'abord, j'utilisais ObjectInputStream.readObject() au lieu de objectInputStream.readUnshared(), il a résolu le problème en partie. Lorsque j'ai augmenté la mémoire de 2048 à 4096, il a commencé à analyser le fichier. BufferedInputStream est déjà utilisé. Du web j'ai trouvé seulement des exemples comment lire des lignes ou des octets, mais rien concernant des objets, performance sage.

Comment puis-je lire le fichier sans augmenter la mémoire de la machine virtuelle Java et éviter l'exception OutOfMemory? Est-il possible de lire des objets à partir du fichier, ne gardant rien d'autre dans la mémoire?

+3

La physique est simple: les fichiers volumineux nécessitent plus de mémoire. Il n'y a pas de magie là-bas. Vos fichiers ne contiennent pas d'objets - ils contiennent des octets qui sont mappés à des chaînes mappées à des objets. – duffymo

+0

Si vous pouvez trier des données dans des cartes pendant que vous lisez le fichier principal, vous pouvez utiliser BufferReader pour lire fichier par ligne, puis utiliser PrintWriter pour ajouter des données au fichier existant ou en créer un nouveau. – Jure

+0

Si les fichiers sont trop gros, vous n'avez pas le choix, mais stockez-les sur le F.S. Lisez ceci: https://commons.apache.org/proper/commons-jcs/ –

Répondre

1

Lors de la lecture de gros fichiers, d'analyser des objets et de les garder en mémoire, il existe plusieurs solutions avec plusieurs compromis:

  1. Vous pouvez adapter à tous les objets analysés en mémoire pour cette application déployée sur un serveur. Il nécessite soit de stocker tous les objets de manière très zippée, par exemple en utilisant octet ou entier pour stocker 2 nombres ou une sorte de décalage dans d'autres structures de données. En d'autres termes, adapter tous les objets dans un espace minimum possible. Ou augmenter la mémoire pour ce serveur (échelle verticalement)

    a) Cependant la lecture des fichiers peut prendre trop de mémoire, vous devez donc les lire en morceaux. Par exemple, c'est ce que je faisais avec les fichiers 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(); 
         } 
        } 
    

    L'idée est d'avoir un moyen d'identifier lorsque certains commence et se termine l'objet et en lecture seule cette partie.

    b) Vous pouvez également diviser les fichiers en plus petits fichiers à la source si vous le pouvez, alors il sera plus facile de les lire.

  2. Vous ne pouvez pas adapter tous les objets analysés pour cette application sur un serveur. Dans ce cas, vous devez partitionner en fonction d'une propriété d'objet. Par exemple, diviser des données basées sur l'état américain en plusieurs serveurs.

Espérons que cela aide votre solution.

+0

Fractionner le fichier en fichiers plus petits à la source a été le plus utile dans mon cas. Je vous remercie! – Kakofonn