嗯,这里有几个问题!
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,否则可能不值得。
例如,如果您每100ms进行一次Young GC,而它需要10ms,那么您就花费了10%的时间在GC上,并且您每秒有10次GC(这非常巨大)。在这种情况下,我不会花费任何时间进行GC调整,因为这10个GC / s仍然存在。
3-一些经验
我在一个应用程序上遇到了类似的问题,该应用程序创建了大量给定类的对象。在GC日志中,我注意到应用程序的创建率约为3 GB / s,这太多了(来吧...每秒3千兆字节的数据?!)。
问题:由于创建了太多的对象而导致太多频繁的GC。
在我的情况下,我附加了一个内存分析器并注意到一个类代表了所有对象的巨大百分比。我追踪了实例化,以发现该类基本上是一个包裹在对象中的布尔值对。在这种情况下,有两个解决方案:
我选择了第二个,因为它对应用程序的影响最小,并且很容易引入。我花了几分钟时间放置了一个具有非线程安全缓存的工厂(我不需要线程安全,因为最终只会有4个不同的实例)。
分配率下降到1 GB / s,年轻GC的频率也相应降低(减少了3倍)。
希望这有所帮助!