将7M行的CSV文件解析为Java对象时的OutOfMemory

将7M行的CSV文件解析为Java对象时的OutOfMemory,java,csv,out-of-memory,Java,Csv,Out Of Memory,我正在逐行提取一个CSV文件,其中包含超过700万行,占用磁盘空间超过1Gig 将操作读入列表很好,不到2分钟。 但问题是,当我尝试在这个列表上循环并将每一行映射到一个对象Balance,然后我创建了一个OuyOfMemoryException: 01:00:30.664 [restartedMain] ERROR org.springframework.batch.core.step.AbstractStep - Encountered an error executing step read

我正在逐行提取一个CSV文件,其中包含超过700万行,占用磁盘空间超过1Gig

将操作读入
列表
很好,不到2分钟。 但问题是,当我尝试在这个列表上循环并将每一行映射到一个对象
Balance
,然后我创建了一个
OuyOfMemoryException

01:00:30.664 [restartedMain] ERROR org.springframework.batch.core.step.AbstractStep - Encountered an error executing step readInputStep in job readCsvJob
java.lang.OutOfMemoryError: GC overhead limit exceeded
    at java.lang.AbstractStringBuilder.<init>(AbstractStringBuilder.java:68) ~[?:1.8.0_172]
    at java.lang.StringBuffer.<init>(StringBuffer.java:128) ~[?:1.8.0_172]
    at java.text.DigitList.getStringBuffer(DigitList.java:804) ~[?:1.8.0_172]
    at java.text.DigitList.getDouble(DigitList.java:164) ~[?:1.8.0_172]
    at java.text.DecimalFormat.parse(DecimalFormat.java:2089) ~[?:1.8.0_172]
    at java.text.NumberFormat.parse(NumberFormat.java:383) ~[?:1.8.0_172]
    at fr.payet.flad.batch.mapper.BalanceLineMapper.parseToDouble(BalanceLineMapper.java:56) ~[classes/:?]
    at fr.payet.flad.batch.mapper.BalanceLineMapper.toBalance(BalanceLineMapper.java:40) ~[classes/:?]
    at fr.payet.flad.batch.tasklet.ReadInputTasklet.execute(ReadInputTasklet.java:56) ~[classes/:?]
和ReadInputAsklet代码:

@Slf4j
@Component
public class ReadInputTasklet implements Tasklet, StepExecutionListener {

    @Autowired
    BalanceLineMapper balanceLineMapper;

    @Override
    public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
        List<Balance> balances = Lists.newArrayList();
        List<String> balancesList = Lists.newArrayList();
        try {
            CSVReader reader = new CSVReader(new FileReader("/Users/ghassen/Desktop/FLAD/Balance_Commune_2016.csv"), '\n');
            String[] nextLine;
            int cursorIndex = 0;
            while ((nextLine = reader.readNext()) != null) {
                if (cursorIndex != 0){
                    balancesList.add(nextLine[0]);
                    log.debug("{} balance(s) ajoutée(s) dans la liste ...", balancesList.size());
                }
                cursorIndex++;
            }
            log.debug("Lecture de toutes les lignes terminé");

            log.debug("Parsing de toutes les lignes");
            for (String line : balancesList){
                String[] lineSeperated = StringUtils.splitByWholeSeparatorPreserveAllTokens(line,";");
                balances.add(balanceLineMapper.toBalance(lineSeperated, cursorIndex));
            }
            log.debug("Job terminé");
        } catch (IOException e) {
            log.error("File not found", e);
        }
        return RepeatStatus.FINISHED;
    }

    @Override
    public void beforeStep(StepExecution stepExecution) {

    }

    @Override
    public ExitStatus afterStep(StepExecution stepExecution) {
        return null;
    }
}
@Slf4j
@组成部分
公共类ReadInputAsklet实现Tasklet、StepExecutionListener{
@自动连线
平衡测线仪平衡测线仪;
@凌驾
public RepeatStatus execute(StepContribution StepContribution,ChunkContext ChunkContext)引发异常{
列表余额=Lists.newArrayList();
List balancesList=Lists.newArrayList();
试一试{
CSVReader reader=新的CSVReader(新的文件阅读器(“/Users/ghassen/Desktop/FLAD/Balance_Commune_2016.csv”),“\n”);
字符串[]下一行;
int cursorIndex=0;
而((nextLine=reader.readNext())!=null){
如果(游标索引!=0){
余额列表添加(下一行[0]);
debug(“{}balance(s)ajoutée(s)dans la liste…”,balancesList.size());
}
cursorIndex++;
}
log.debug(“路线终点站讲座”);
debug(“解析toutes les lignes”);
用于(字符串行:balancesList){
String[]lineseparated=StringUtils.splitbywholeparatorreservealltokens(行“;”);
添加(balanceLineMapper.toBalance(线分隔,粗略索引));
}
log.debug(“作业终端”);
}捕获(IOE异常){
log.error(“未找到文件”,e);
}
返回RepeatStatus.FINISHED;
}
@凌驾
预处理前的公共无效(步骤执行步骤执行){
}
@凌驾
公共出口状态后步骤(步骤执行步骤执行){
返回null;
}
}

您正在短时间内创建大量实例(包括稍后解析的字符串),垃圾回收器无法跟上这些实例。我建议您在流设计中构建整个系统,并且只解析您实际需要的实例。

您在短时间内创建了大量实例(包括稍后解析的字符串),垃圾收集器无法跟上这些实例。我建议您以流式设计构建整个系统,并且只解析您实际需要的系统。

我同意@AUser。不过,让我说得更具体一些。您可以用标准的Double.valueOf()替换parseToDouble函数。它应该更有效率。

我同意@AUser的观点。不过,让我说得更具体一些。您可以用标准的Double.valueOf()替换parseToDouble函数。它应该更高效。

我以前的解决方案是直接解析读取行并将其添加到
列表中。我需要所有这些,因为在那之后我会将它们保存在数据库中。我以前的解决方案是直接解析读取行并将其添加到
列表中。我需要所有这些,因为之后我会将它们持久化到数据库中。我不知道Spring,但您可能需要增加它的堆设置-Xmx将是普通JVM的相关命令行参数,例如,-Xmx6G将上限设置为6GB。也许是这样的:我不知道Spring,但您可能需要增加它的堆设置-Xmx将是普通JVM的相关命令行参数,例如,-Xmx6G将上限设置为6GB。也许这样:你是对的。。我删除了方法
Double parsetdouble(字符串编号)
,现在它很好:)你是对的。。我删除了方法
Double parsetdouble(字符串编号)
,现在可以了:)
@Slf4j
@Component
public class ReadInputTasklet implements Tasklet, StepExecutionListener {

    @Autowired
    BalanceLineMapper balanceLineMapper;

    @Override
    public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
        List<Balance> balances = Lists.newArrayList();
        List<String> balancesList = Lists.newArrayList();
        try {
            CSVReader reader = new CSVReader(new FileReader("/Users/ghassen/Desktop/FLAD/Balance_Commune_2016.csv"), '\n');
            String[] nextLine;
            int cursorIndex = 0;
            while ((nextLine = reader.readNext()) != null) {
                if (cursorIndex != 0){
                    balancesList.add(nextLine[0]);
                    log.debug("{} balance(s) ajoutée(s) dans la liste ...", balancesList.size());
                }
                cursorIndex++;
            }
            log.debug("Lecture de toutes les lignes terminé");

            log.debug("Parsing de toutes les lignes");
            for (String line : balancesList){
                String[] lineSeperated = StringUtils.splitByWholeSeparatorPreserveAllTokens(line,";");
                balances.add(balanceLineMapper.toBalance(lineSeperated, cursorIndex));
            }
            log.debug("Job terminé");
        } catch (IOException e) {
            log.error("File not found", e);
        }
        return RepeatStatus.FINISHED;
    }

    @Override
    public void beforeStep(StepExecution stepExecution) {

    }

    @Override
    public ExitStatus afterStep(StepExecution stepExecution) {
        return null;
    }
}