维护一个经常使用的对象池,从中获取一个对象而不是新建一个对象的优缺点是什么?这有些类似于字符串驻留,但适用于所有类对象。
例如,这可以被认为是好的,因为它可以节省垃圾回收时间和对象创建时间。另一方面,如果从多个线程中使用,它可能会成为同步瓶颈,需要显式释放并引入内存泄漏的可能性。通过绑定可以回收的内存,它给垃圾回收器增加了额外的压力。
维护一个经常使用的对象池,从中获取一个对象而不是新建一个对象的优缺点是什么?这有些类似于字符串驻留,但适用于所有类对象。
例如,这可以被认为是好的,因为它可以节省垃圾回收时间和对象创建时间。另一方面,如果从多个线程中使用,它可能会成为同步瓶颈,需要显式释放并引入内存泄漏的可能性。通过绑定可以回收的内存,它给垃圾回收器增加了额外的压力。
优化的第一定律:不要进行优化。第二定律:除非你已经测量并确切知道需要在哪里进行优化。
只有当对象创建成本非常高,并且它们可以被重用(只需使用公共操作将其状态重置为可重用状态)时,才能起到作用。
您提到的两个好处并不是真正的好处:Java中的内存分配是免费的(成本接近于10个CPU指令,这几乎可以忽略不计)。因此,减少对象的创建只能节省在构造函数中花费的时间。对于可以重复使用的真正重型对象(如数据库连接、线程),这可能会带来好处:您可以重用相同的连接、相同的线程。
GC时间不会减少。事实上,它可能会更糟。对于移动代GC(Java是,或者直到1.5),GC运行的成本取决于存活对象的数量,而不是释放的内存。存活对象将在被标记为“旧”的之前,在内存中的另一个空间中移动几次(这就是使内存分配变得如此快的原因:每个GC块内的空闲内存是连续的),然后被移入较老的代内存空间。
编程语言和支持,如GC,是针对普遍使用而设计的。如果你在许多情况下偏离常规用法,你可能会得到更难读的代码,也不够高效。
除非创建该对象的成本很高,否则我不会费心。
好处:
缺点:
您是否有实际要解决的问题,还是这只是一种推测?除非您进行了基准测试/分析运行,否则我不会考虑执行此类操作。
完全取决于创建对象的成本与创建次数的比较……例如,仅包含一些字段且没有方法(除了访问器)的对象可以是池化的一个真实用例。
一个真实的例子:我需要重复地从生成大量整数/排名对的过程中提取前n个最高排名的项目(整数)。我在有界优先级队列中使用了一个“pair”对象(一个整数和一个浮点排名值)。重复使用这些配对对象而不是清空队列、丢弃配对对象并重新创建它们,可提高20%的性能...主要体现在GC负担上,因为这些配对对象在JVM的整个生命周期中都不需要重新分配。
对象池通常只适用于昂贵的对象,如数据库连接。在Java 1.4.2之前,对象池可以提高性能,但在Java 5.0中,对象池更可能会损害性能,而不是帮助性能,并且通常会删除对象池以提高性能(和简单性)。
我同意Jon Skeet的观点,如果您没有特定的理由创建对象池,那么就没必要费力去做了。
但是,在某些情况下,对象池确实非常有用/必要。例如,如果您有一个需要花费大量成本来创建但可以重复使用的资源(例如数据库连接),那么使用对象池可能是明智的选择。此外,在数据库连接的情况下,对象池有助于防止您的应用程序打开太多并发连接到数据库。