我正在使用java代码处理一个巨大的CSV(1GB)。
我的应用程序在具有8GB内存的2台Core Machine上运行。
我正在使用以下命令启动我的应用程序。
java -Xms4g -Xmx6g -cp $CLASSPATH JobSchedulerService
Applcation启动一个线程,从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);
}
答案 0 :(得分:0)
1)将大尺寸文件拆分成小尺寸文件。
2)按顺序或并行处理每个文件。
检查小尺寸分割文件的链接:https://stackoverflow.com/a/2356156/8607192
或
使用Unix命令“split for split for size”。
答案 1 :(得分:0)
我找到了OOM的理由。 虽然我正在以正确的方式阅读文件。一旦我完成处理,就逐行读取文件并丢弃旧行。所以这不会造成问题。
问题是当我向数据库编写相同内容时。
我的代码在Transactional块中运行,因为在事务完成之前不会释放哪些实体。简而言之,所有3M实体都会保留在内存中,直到交易完成为止。
一旦我在可疑对象中添加了finalize方法,我就能够得出这个结论。我所能看到的是,DTOS(临时Pojo)以非常快的速度被丢弃,但是甚至没有被丢弃的单个实体。最后,所有实体都被丢弃了。
答案 2 :(得分:-1)
您尚未关闭 InputStream inputSteam
关于 s3object.getObjectContent() 获取包含此对象内容的输入流。
注意:该方法是一个简单的 getter,实际上并不创建流。如果您检索 S3Object,则应尽快关闭此输入流,因为对象内容不会缓存在内存中,而是直接从 Amazon S3 流式传输。此外,未能关闭此流可能会导致请求池被阻塞。