为什么这段代码运行得越来越慢?

时间:2011-04-19 22:33:43

标签: java hibernate

我有一个名为SrcFile的实体类,其中一个列是:

@NotNull
@Lob
private Byte[] data;

SrcFile与报表实体具有OneToOne关系。

来自Report.java:

@OneToOne
private SrcFile srcFile;

坚持SrcFile实体效果很好。

srcFileHomeFacade.clearInstance();
SrcFile srcFile = srcFileHomeFacade.getInstance();
byte[] bArray = resource.getBytesForSource();
srcFile.setData(ReportFileResource.toObject(bArray));
System.out.println("````````````````srcFile data length: "+bArray.length);
srcFileHomeFacade.persist();

当我坚持Report时会出现问题。

我做:

report.setSrcFile(srcFile);
reportHomeFacade.persist();

并且工作得很好但是在多次运行此代码之后会变得越来越慢(即使它会引发GC开销错误)并且经过数小时的调查后我发现这个report.setSrcFile(srcFile)是问题所在

不知何故报道不喜欢引用srcFile.data ...

这样的数量

你看到原因吗?

如果我评论report.setSrcFile一切都很好(除了报告表中的SRCFILE_ID为空,但它只是用于测试)。请注意,数据长度约为100.000。

注意:如果我没有保留任何report但只保留srcFile个实体,我就没有问题。 的更新

“运行速度越来越慢”解释:调用此代码将一些pcl转换为pdfs,因此data包含pcl的来源,每次都不同。转换大约100个pcls后,进程变得越来越慢,使用VM我发现这个byte []数组占用了大量的MB内存。同样,它绝对不是关于IO的问题,但关于报告实体上的这个setSrcFile,VisualVM也表明了这一点。

2 个答案:

答案 0 :(得分:2)

我仍然有点不确定,但我怀疑你的问题与你持久化和处理实体对象的方式有关:如果你的实体在持久存在后正确地丢弃它们,GC应该经常释放内存以保持你的系统运行顺畅。特别是如果你在每次事务后使用flush()或commit(),你的内存使用量应该不会累积太多。但是,在您的情况下,似乎所有实体即使在不再需要之后也会保留在内存中 - 因此必须有一些原因可以解释为什么资源不会被释放。

你是否有机会使用单个for循环迭代一组srcFiles并直接在其中调用所有persist()?如果是这样,您的问题可能与范围有关。您可以尝试将循环的内容提取到一个新方法,以便在每次迭代后正确释放所有局部变量。

您也可以通过设置CascadeType.PERSIST或CascadeType.ALL并在报表上使用单个persist()操作来保存两个对象,从而改进。 FetchType.LAZY也可能会有所帮助。

在任何情况下:查找程序将所有实体直接保留在内存中的可能原因,而不是将它们保存到数据库中,然后忘记它们。

答案 1 :(得分:0)

我记得BLOB的原生JDBC接口可能很棘手,需要手动关闭()供应商对象。如果错过了这一步,则BLOB会在JDBC驱动程序上积累(即在JVM内存中),最终JVM也会在OOM中累积。

我想知道您是否需要任何供应商特定的属性或步骤来保存后关闭BLOB。