[英]java.lang.OutOfMemoryError While processing a Large CSV file
我正在使用 java 代码处理一个巨大的 CSV (1GB)。
我的应用程序在具有 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);
}
1) 将大文件拆分为小文件。
2) 依次或并行处理每个文件。
检查小尺寸拆分文件的链接: https : //stackoverflow.com/a/2356156/8607192
或者
使用 Unix 命令“split for split based on size”。
我找到了 OOM 的原因。 虽然我正在以正确的方式阅读文件。 处理完后,逐行读取文件并丢弃旧行。 所以这不会造成问题。
问题是当我将相同的内容写入数据库时。
我的代码在事务块中运行,因为在事务完成之前不会释放实体。 简而言之,所有 3M 实体都保存在内存中,直到提交事务。
一旦我在我的可疑对象中添加了 finalize 方法,我就能够得出这个结论。 我所看到的只是 DTOS(临时 Pojo)以非常快的速度被丢弃,但甚至没有丢弃一个实体。 最后一下子所有的实体都丢弃了。
您还没有关闭 InputStream inputSteam
关于 s3object.getObjectContent() 获取包含此对象内容的输入流。
注意:该方法是一个简单的 getter,实际上并不创建流。 如果您检索 S3Object,则应尽快关闭此输入流,因为对象内容不会缓存在内存中,而是直接从 Amazon S3 流式传输。 此外,未能关闭此流可能会导致请求池被阻塞。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.