Hibernate批量插入内存泄漏

时间:2014-11-27 21:00:51

标签: java mysql performance hibernate batch-processing

我面临一个我无法解决的问题。

我正在使用hibernate进行批量插入,一切正常,它应该配置,它的批处理插入,我检查了mysql日志以查看说明,但问题是,即使我刷新会话,它不释放内存,只是一点点,我使用配置文件检查并且所有内存都被HashMap保留,即使我清除了这个哈希映射。

查看下面的代码。

long contador = 0;
final int NUMERO_REGISTROS_GRAVAR = 5000;
Map<String, ContatoBean> mapaContatos = new HashMap<>(NUMERO_REGISTROS_GRAVAR);
final Reader inputStreamReader = new InputStreamReader(new BufferedInputStream(stream));
final String nomeTemplate = parametros.get("cmpTemplateMailing");
final MailingTemplateBean mailingTemplate = MailingService.getInstance().getMailingTemplate(nomeTemplate);
MailingFactory mailingFactory = new MailingFactory(mailingTemplate);
Session ss = HibernateUtil.getCurrentSession();

try (CSVParser csvParser = CSVFormat
                               .newFormat(';')
                               .withHeader(mailingFactory.getCabecalho())
                               .withSkipHeaderRecord(true)
                               .parse(inputStreamReader))
{
  Iterator<CSVRecord> iterator = csvParser.iterator();

  MailingBean mailing = new MailingBean();

  mailing.setNmNome(nomeArquivo.substring(0, nomeArquivo.lastIndexOf(".")));
  mailing.setDsDescricao(parametros.get("descricao") != null ? parametros.get("descricao") : "Sem Descrição");
  mailing.setIcAtivo("Sim");
  mailing.setMailingTemplate(mailingTemplate);

  ss.save(mailing);

  while (iterator.hasNext())
  {
    CSVRecord registro = iterator.next();

    String cpf = registro.get(mailingTemplate.getCampoUnicoIdentificador());

    ContatoBean contato = mapaContatos.get(cpf);

    if (contato == null)
    {
      contato = mailingFactory.buildContatoFromTemplate(registro, mailing);
      contador++;

      if (contador >= NUMERO_REGISTROS_GRAVAR)
      {
        contador = 0;
        mapaContatos.clear();
        ss.flush();
        ss.clear();
      }
    }

    mailingFactory.atualizarNumeroContato(registro, contato);

    mapaContatos.put(cpf, contato);

    ss.saveOrUpdate(contato);
  }

  ss.flush();
  ss.clear();
  ss.getTransaction().commit();
}
catch (Exception ex)
{
  ss.getTransaction().rollback();
  throw new SistemaException(ex);
}
finally
{
  IOUtils.closeQuietly(inputStreamReader);
  IOUtils.closeQuietly(stream);
  mapaContatos.clear();
}

这是解析csv文件并在数据库中保存一些记录的代码。

这是来自Profiler的一些屏幕抱歉链接,我不能发布图片由于在这里是新的:(

之前我强制使用GC

https://dl.dropboxusercontent.com/u/17155314/Before%20GC.png

之后我强制使用GC

https://dl.dropboxusercontent.com/u/17155314/After%20GC.png

正如您在图表中看到的,它开始分配内存并释放一些内存,但不是所有已分配的内存。

重要的是,它只是使用了200 MB的内存,不像应用程序在具有32 gb等内存的服务器上运行,问题是,我刚刚启动了应用程序,并在生产中进行了测试以收集数据导入数据的数量要多得多,并且由于没有释放内存而导致一些导入的内存不足。

任何提示?

我的Hibernate.cfg用于批量插入

    <property name="hibernate.jdbc.batch_size">5000</property>
    <property name="hibernate.order_inserts">true</property>
    <property name="hibernate.order_updates">true</property>
    <property name="hibernate.cache.use_query_cache">false</property>

我使用5000作为批量大小,因为数据的导入量类似于400k~2kk记录,如果设置较低值则需要很长时间来处理。

我在使用WildFly 8.1的Java EE应用程序中使用Hibernate和Mysql

1 个答案:

答案 0 :(得分:0)

我建议您尝试仅为批处理提交事务。提交2M记录插入事务将会破坏撤消/重做日志。

另外请确保您不使用IDENTITY生成器,因为它只是禁用JDBC批处理。