好吧,这里有几个问题!
1 - 如何管理短期对象?
如前所述,JVM 可以完美地处理大量短期对象,因为它遵循弱世代假设。
请注意,我们说的是到达主内存(堆)的对象。这并非总是如此。您创建的许多对象甚至没有留下 CPU 寄存器。例如,考虑这个 for 循环
for(int i=0, i<max, i++) {
// stuff that implies i
}
让我们不要考虑循环展开(JVM 在您的代码上大量执行的优化)。如果max
等于Integer.MAX_VALUE
,则循环可能需要一些时间来执行。但是,i
变量永远不会逃脱循环块。因此 JVM 会将该变量放入 CPU 寄存器中,定期递增它,但永远不会将其发送回主存。
因此,如果仅在本地使用它们,创建数百万个对象并不是什么大问题。它们在存储在 Eden 之前就已经死亡,因此 GC 甚至不会注意到它们。
2 - 减少 GC 的开销有用吗?
像往常一样,这取决于。
首先,您应该启用 GC 日志记录以清楚地了解正在发生的事情。您可以使用 启用它-Xloggc:gc.log -XX:+PrintGCDetails
。
如果您的应用程序在 GC 周期中花费大量时间,那么,是的,调整 GC,否则,它可能不值得。
例如,如果您每 100 毫秒有一个年轻 GC,需要 10 毫秒,那么您将 10% 的时间花在 GC 上,并且每秒有 10 次收集(这是 huuuuuge)。在这种情况下,我不会花任何时间在 GC 调优上,因为那 10 GC/s 仍然存在。
3 - 一些经验
我在创建大量给定类的应用程序上遇到了类似的问题。在 GC 日志中,我注意到应用程序的创建速率约为 3 GB/s,这太高了(来吧……每秒 3 GB 的数据?!)。
问题:创建的对象太多导致频繁的GC。
在我的例子中,我附加了一个内存分析器,并注意到一个类代表了我所有对象的很大一部分。我追踪了实例,发现这个类基本上是一对包裹在对象中的布尔值。在这种情况下,有两种解决方案可用:
我选择了第二个,因为它对应用程序的影响最小并且易于引入。我花了几分钟的时间来放置一个带有非线程安全缓存的工厂(我不需要线程安全,因为我最终只有 4 个不同的实例)。
分配速率下降到 1 GB/s,年轻 GC 的频率也下降了(除以 3)。
希望有帮助!