2017-09-14 128 views
0

我正在使用java代碼處理巨大的CSV(1GB)。java.lang.OutOfMemoryError處理大型CSV文件時

我的應用程序運行在具有8GB內存的2核心機器上。

我正在使用以下命令啓動我的應用程序。

java -Xms4g -Xmx6g -cp $CLASSPATH JobSchedulerService 

應用程序啓動一個線程從S3下載CSV並處理它。 應用程序工作文件一段時間,但OutOfMemoryError處理文件的一半。

我正在尋找一種方法,可以繼續處理CSV文件,同時保持較低的內存使用量。

在CSV過程

我執行以下步驟:

//Step 1: Download FROM S3 
String bucketName = env.getProperty(AWS_S3_BUCKET_NAME); 
AmazonS3 s3Client = new AmazonS3Client(credentialsProvider); 
S3Object s3object = s3Client.getObject(new GetObjectRequest(bucketName, key)); 
InputStream inputSteam = s3object.getObjectContent(); //This Stream contains about 1GB of data 

//Step 2: Parse CSV to Java 
ObjectReader oReader = CSV_MAPPER.readerFor(InboundProcessing.class).with(CSV_SCHEMA); 
try (FileOutputStream fos = new FileOutputStream(outputCSV, Boolean.FALSE)) { 
    SequenceWriter sequenceWriter = CsvUtils.getCsvObjectWriter(InboundProcessingDto.class).writeValues(fos); 
    MappingIterator<T> mi = oReader.readValues(inputStream) 

    while (mi.hasNextValue()) { 
     InboundProcessing inboundProcessing = mi.nextValue(); 
     inboundProcessingRepository.save(inboundProcessing); // this is Spring JPA Entity Save operation. (Almost 3M records so 3M calls)      
     sequenceWriter.write(inboundProcessingDto); // this is writing to a CSV file on local file system which is uploaded to S3 in next Step 
    } 
} catch (Exception e) { 
    throw new FBMException(e); 
} 
+2

看起來你正在將整個事物一次讀入記憶。這是必要的嗎? – pvg

+1

如果您的開始命令確實包含'java -Xms4g -Xms6g ...',則應將其更正爲'java -Xms4g -Xmx6g ...'。 – blafasel

+0

謝謝。 這是一個錯字。 – Pramod

回答

0

我找到了OOM的原因。 雖然我正在閱讀文件的方式。一行一行地讀取文件,並在完成處理後立即丟棄舊行。所以這不會造成問題。

問題是當我寫入數據庫時​​。

我的代碼在Transactional塊中運行,因爲在事務完成之前哪些實體不會被釋放。總之,所有的3M實體都保存在內存中,直到交易完成。

一旦我在可疑對象中添加了最終化方法,我就能夠達成這個結論。我所能看到的是,DTOS(臨時Pojo)以非常快的速度被丟棄,但是甚至沒有丟棄單個實體。最後所有的實體都被拋棄了。

0

1)拆分大尺寸文件到小尺寸的文件。

2)按順序或並行處理每個文件。

檢查鏈接分割文件體積小:https://stackoverflow.com/a/2356156/8607192

或者

使用UNIX命令「分裂根據大小分」。