2017-09-14 130 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命令“分裂根据大小分”。