Java对象重用

时间:2008-12-30 20:50:00

标签: java

Java Objects是否应该重复使用,因为它可以重复使用?或者我们应该只在它们是“重量级”时重用它,即有与之相关的操作系统资源吗?

互联网上的所有旧文章都尽可能地谈论对象重用和对象池,但是我已经阅读了最近的文章,说new Object()现在已经高度优化(10条指令),对象重用不是那么大像以前一样处理。

目前的最佳做法是什么,以及您是如何做到的?

8 个答案:

答案 0 :(得分:15)

我让垃圾收集器为我做了那种决定,唯一一次我用新分配的对象达到堆限制是在运行一个错误的递归算法几秒后生成3 * 27 * 27 ..新对象尽可能快。

做最好的可读性和封装。有时重用对象可能很有用,但通常你不应该担心它。

答案 1 :(得分:14)

如果您使用它们密集并且构造成本高昂,您应该尽可能多地重复使用它们。

如果您的对象非常小,并且创建起来很便宜(比如Object),那么您应该创建新对象。

例如,汇集连接数据库,因为创建新数据库的成本高于创建.. mmhh new Integer的成本。

所以你的问题的答案是,当它们很重的时候重复使用 AND 经常使用(不值得汇集一个只使用两次的3 mb对象)

修改

此外,Effective Java:Favor Immutability中的这个项目值得一读,可能适用于您的情况。

答案 2 :(得分:8)

让垃圾收集器完成它的工作,可以认为它比你的代码更好。

除非剖析器证明它有罪。并且甚至不使用常识来试图弄清楚何时出错。在不寻常的情况下,甚至像字节数组这样的廉价对象也会更好地汇集。

  • 优化规则1:不要这样做。
  • 规则2(仅限专家):不要这样做。

答案 3 :(得分:7)

对象创建很便宜,是的,但有时不够便宜。

如果你快速连续创建了很多(我的意思是很多)临时对象,垃圾收集器的成本是相当可观的。然而,即使有良好的分析器,您也不一定能够轻松地看到成本,因为垃圾收集器现在可以在短时间内工作,而不是阻止整个应用程序停留一两秒。

我在项目中获得的大多数性能改进来自于通过积极的缓存来避免对象创建或避免整个工作(包括对象创建)。无论对象有多大或多小,它仍然需要时间来创建它并管理它的引用和堆结构。 (当然,清理和内部堆碎片整理/复制也需要时间。)

我不会开始以所有成本避免对象创建,但如果你在内存分析器中看到一个拼图模式,那就意味着你的垃圾收集器处于重负荷状态。如果您的垃圾收集器使用CPU,则CPI不适用于您的应用程序。

关于对象池:正确执行并且没有遇到内存泄漏或无效状态,或者在管理上花费的时间比保存时要困难。所以我从未使用过这种策略。

我的策略是简单地争取不可变对象。不可变的东西可以很容易地缓存,因此有助于保持系统简单。

但是,无论您做什么:确保首先使用分析器检查您的热点。过早优化是最邪恶的根源。

答案 4 :(得分:3)

经验法则应该是使用您的常识并在其创建消耗重要资源时重用对象,例如I / O,网络流量,数据库连接等......

如果它只是创建一个新的String(),忘记重用,你将从中获得任何好处。代码可读性具有更高的偏好。

答案 5 :(得分:3)

如果出现性能问题,我会担心。首先做一些有意义的事情(你会用灵长来做这件事),如果你然后运行一个分析工具并发现它是新的导致你的问题,开始考虑预分配(即你的程序没有做太多的工作) )。

重复使用对象听起来像是等待发生的灾难:

SomeClass someObject = new SomeClass();

someObject.doSomething();
someObject.changeState();
someObject.changeOtherState();
someObject.sendSignal();
// stuff

//re-use 
someObject.reset(); // urgh, had to put this in to support reuse
someObject.doSomethingElse(); // oh oh, this is wrong after calling changeOtherState, regardless of reset
someObject.changeState(); // crap, now this is wrong but it's not obvious yet
someObject.doImportantStuff(); // what's going on?

答案 6 :(得分:1)

对象创建肯定比以前更快。 JDK 5及更高版本中的新一代GC也在改进中。

我认为这些都不会使对象的过度创建成本低廉,但它们确实降低了对象池的重要性。我认为池对数据库连接有意义,但我不会尝试将它用于我自己的域对象。

重用可以提高线程安全性。您需要仔细考虑以确保可以安全地重用对象。

如果我认为对象重用很重要,我会使用Terracotta,Tangersol,GridGain等产品,并确保我的服务器有大量可用的内存。

答案 7 :(得分:1)

以上评论。

不要尝试再次猜测GC和Hotspot。对象池可能只有一次有用,但是这些日子除非你在讨论数据库连接或独特的系统资源,否则它不太有用。

尝试编写干净简单的代码,并对Hotspot可以做的事情感到惊讶。

为什么不使用VisualVM或分析器来查看代码?