Java性能逐渐下降

4

我有一个Java类,它做了这样的事情:

public void slowsDownOverTime() {
    for (int i=0 ; i<nIter ; i++) {
        BigObject bigObject = new BigObject();
        // some code here that populates big object ...
        CustomSerializer.write(bigObject);
    }
}

我观察到的是,随着代码的迭代,序列化器写入所需的时间越来越长。当它开始运行时,序列化器只需要几毫秒的时间;经过数万次迭代后,它需要几秒钟才能运行。
当发生这种情况时,序列化器写入的磁盘并没有接近满,使用的 Java 堆空间也没有接近最大值。
尽可能地减少在此周期中创建和销毁的对象的数量和大小。这基本上耗尽了我解决这类问题的工具!
如何理解和纠正逐渐恶化的性能下降,请给予任何建议!

如果您定期调用 System.gc()(例如每 10_000 次迭代),问题是否仍然存在? - Turing85
1
只有 CustomSerializer.write 是慢的吗?你是在追加到文件中吗? - matt
4
问题可能与write方法内部发生的事情有关,而不是对象本身。 - GotoFinal
2
我同意@GotoFinal所说的。不过,我想补充一点,也许最简单的找出问题所在的方法是使用分析器。一个简单的采样分析器就可以解决问题,在Java中有很多选择,例如VisualVM(我相信它仍然随JDK一起提供)。 - Dolda2000
2
你尝试过对代码进行性能分析吗? - apangin
显示剩余7条评论
2个回答

1
经过与jvisualvm的分析无果后,我不得不添加了大量日志。这让我意识到问题出在执行用于填充BigObject的Hibernate操作上。当我检索到每个对象后,立即将其清除,从而解决了性能问题。
虽然我不是Hibernate专家,但我认为发生的情况是,即使对象在我的代码中超出了范围(因此被垃圾回收),Hibernate仍在其缓存中保留了每个对象的副本。然后,当它执行下一个检索时,它会将检索到的对象与所有缓存的对象进行比较。随着缓存数量的增加,这个操作所需的时间会越来越长。

1

我认为,这是由于遗漏了代码(这里有一些填充大对象的代码...)导致的。请尝试以下代码:

public void slowsDownOverTime() {
    BigObject bigObject = new BigObject();
    // some code here that populates big object ...
    for (int i=0 ; i<nIter ; i++) {
        CustomSerializer.write(bigObject);
    }
}

这将始终写入相同的对象,我希望其性能不会降低。
我认为被省略的代码构建了一个不断增长的数据结构,由bigObject引用。请记住,在序列化时,Java会遍历所有依赖对象并序列化所有依赖对象。因此,每次迭代都会写入越来越多的数据。这可能是性能下降和磁盘空间占用过多的原因。

从技术上讲,我认为你的意思是将填充大对象的代码放入循环中。你写的方式会导致相同的对象内容每次都被写入,而我在顶部的代码则每次写入不同的内容。 - quarkpt
我仔细查看了代码,它与此示例非常接近,除了我的更正,而不是我最初的理解。BigObject实例在循环的每次迭代中都是相同的,但其内容会发生变化。我已将必要的更改最小化(即,许多BigObject成员从一次迭代到下一次迭代都是相同的--不仅是内容,而且是实际对象;因此,成为BigObject成员的对象的创建/销毁被最小化)。 - quarkpt
我的建议是(针对测试),将填充bigObject的代码放在循环外面。这样每次迭代都会写入相同的数据。然后将其与您的版本进行比较。 - Donat
在进行序列化的循环之外填充bigObject的测试中(因此仍然每次序列化nIter次,但是每次都是相同的对象),没有检测到明显的减速。 - quarkpt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接