簡體   English   中英

在Java中讀取大文件時如何避免OutOfMemory異常

[英]How to avoid OutOfMemory exception while reading large files in Java

我正在研究從文件讀取大量數據的應用程序。 基本上,我有一個巨大的文件(大約1.5-2個演出),其中包含不同的對象(每個文件約5至1000萬個對象)。 我需要閱讀所有內容,並將其放置在應用程序中的不同地圖上。 問題在於該應用程序在某些時候讀取對象時內存不足。 僅當我將其設置為使用-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. 您無法在一台服務器上容納該應用程序的所有解析對象。 在這種情況下,您必須基於某些對象屬性進行分片。 例如,將基於美國州的數據拆分為多個服務器。

希望它對您的解決方案有所幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM