创建(和发布)数百万个小对象的“最佳实践”是什么?
我正在用Java编写一个国际象棋程序,搜索算法为每一个可能的移动生成一个“移动”对象,一次标称搜索每秒可以轻松生成超过一百万个移动对象。JVM GC已经能够处理我的开发系统上的负载,但我有兴趣探索以下替代方法:
绝大多数对象的寿命都很短,但生成的移动中约有1%是持久化的,并作为持久化值返回,因此任何池或缓存技术都必须提供排除特定对象重复使用的能力。
我不期望完全充实的示例代码,但我将感谢进一步阅读/研究的建议,或类似性质的开源示例。
好吧,这里有几个问题!
1-如何管理短期对象?
如前所述,JVM可以完美地处理大量短期对象,因为它遵循弱世代假设。
请注意,我们谈论的是到达主存储器(堆)的对象。情况并非总是如此。您创建的许多对象甚至没有留下CPU寄存器。例如,考虑一下这个for循环
for(int i=0, i<max, i++) {
// stuff that implies i
}
让我们不要考虑循环展开(JVM在您的代码上大量执行的优化)。如果max
等于intger.MAX_VALUE
,您的循环可能需要一些时间来执行。但是,i
变量永远不会转义循环块。因此JVM会将该变量放入CPU寄存器中,定期递增但永远不会将其发送回主存储器。
所以,如果只在本地使用,创建数百万个对象没什么大不了的。它们在存储在伊甸园之前就已经死了,所以GC甚至不会注意到它们。
2-减少GC的开销有用吗?
像往常一样,这要看情况而定。
首先,您应该启用GC日志记录以清楚地了解正在发生的事情。您可以使用-Xloggc:gc.log-XX: PrintGC细节
启用它。
如果您的应用程序在一个GC周期中花费了大量时间,那么,是的,请调整GC,否则,这可能不值得。
例如,如果您每100ms有一个年轻的GC,需要10ms,那么您将花费10%的时间在GC中,并且每秒有10个集合(即huuuuge)。在这种情况下,我不会花任何时间进行GC调优,因为这10个GC/s仍然存在。
3-一些经验
我在创建大量给定类的应用程序上遇到了类似的问题。在GC日志中,我注意到应用程序的创建速率约为3 GB/s,这太多了(拜托...每秒3 GB的数据?!)。
问题:由于创建的对象过多,导致频繁的GC过多。
在我的例子中,我附加了一个内存分析器,并注意到一个类代表了我所有对象的很大一部分。我跟踪了这些实例,发现这个类基本上是一对封装在对象中的布尔值。在这种情况下,有两种解决方案:
>
修改算法,这样我就不会返回一对布尔值,而是有两个方法分别返回每个布尔值
缓存对象,知道只有4个不同的实例
我选择了第二个,因为它对应用程序的影响最小,并且易于介绍。我花了几分钟时间才建立一个具有非线程安全缓存的工厂(我不需要线程安全,因为我最终只有4个不同的实例)。
分配速率降到了1 GB/s,年轻GC的频率也降到了1 GB/s(除以3)。
希望这有帮助!
自版本6以来,JVM的服务器模式采用了转义分析技术。使用它可以避免GC。
使用详细垃圾回收运行应用程序:
java -verbose:gc
它会告诉你什么时候收集。会有两种类型的扫描,快速扫描和全面扫描。
[GC 325407K->83000K(776768K), 0.2300771 secs]
[GC 325816K->83372K(776768K), 0.2454258 secs]
[Full GC 267628K->83769K(776768K), 1.8479984 secs]
箭头是之前和之后的大小。
只要它只是执行GC而不是完整的GC,您就安全到家了。常规GC是“年轻一代”中的副本收集器,因此不再引用的对象只是被遗忘,这正是您想要的。
阅读Java SE 6 HotSpot虚拟机垃圾收集调优可能会有所帮助。
在Java页面对象模型中创建步骤时实例化对象的最佳方法是什么? 有人知道Cucumber脚本是如何编译的吗? 我想,如果一切都建成并符合要求,下面的第二个或第三个选项可能是最好的方法。 如果只编译与正在执行的测试相关的步骤,那么我想这将是第一个。 我举了以下例子: 以上所有步骤(在同一个LoginSteps.java类中加上更多)从以下开始 这是最好的方法,还是创建单个实例更好? 或者在Login
问题内容: 我需要弄清楚如何创建一个临时日历对象(已经存在的“永久”日历的副本),以便可以操纵该副本:tempCal.add(单位,值)。我需要保持原始日历对象不变,所以我真的不想直接在其上调用add(unit,value)。 由于我创建副本的尝试均无济于事,因此,我目前的丑陋方法是调用永久性Cal.add(单位,值),显示所需的结果,然后调用永久性Cal.add(单位,-值),这似乎是,不酷。
问题内容: 好吧,这并不是一个问题,因为我并没有真正“卡住”我的代码,但是我发现Android API在访问外部存储设备和File.createTempFile()方法方面有些奇怪的行为, d想了解正在发生的事情… 请注意,我的清单 中不 包含。 第1部分 : 我有以下代码,它 确实可以 发挥作用: 它会为我创建一个临时文件,并且我可以毫无问题地在其中写入数据。 问题1 :为什么该功能有效,因为我
本文向大家介绍ThreadPoolExecutor 创建方法最佳实践?相关面试题,主要包含被问及ThreadPoolExecutor 创建方法最佳实践?时的应答技巧和注意事项,需要的朋友参考一下 在《阿里巴巴 Java 开发手册》“并发处理”这一章节,明确指出线程资源必须通过线程池提供,不允许在应用中自行显示创建线程。 为什么呢? 使用线程池的好处是减少在创建和销毁线程上所消耗的时间以及系统资源开
问题内容: 我想在Django中创建多个用户。我想知道哪种方法最好。 还是应该使用.. 还是我必须创建自定义用户模型…这将对创建多种类型的用户非常有用… ?? 问题答案: Django没有多个用户-它只有一个用户,然后根据权限,用户可以执行不同的操作。 因此,首先-django中只有一种用户类型。如果你使用默认的身份验证框架,则从将此用户的模型称为。 如果要自定义django中的用户行为,可以执行
问题内容: 要创建一个空的JSON对象,我通常使用: 将null强制转换为对象有效,但是此解决方案是否还有其他更好的方法和/或任何问题? 问题答案: 您的解决方案可以工作。 该文档指定将导致一个空的对象,因此可能有人说您的代码有效,这是使用的方法。 PHP:对象-手册 如果将任何其他类型的值转换为对象,则将创建stdClass内置类的新实例。如果值为NULL,则新实例将为空。 ..但是,请尝试确保