对象池

维护经常使用的对象池并从池中抓取一个而不是创建新对象的专业人员和成员是什么? 类似于字符串实习的东西,除了它可以用于所有类对象。

例如,它可以被认为是好的,因为它节省了gc时间和对象创建时间。 另一方面,如果从多个线程使用它,它可能是同步瓶颈,需要显式释放并引入内存泄漏的可能性。 通过占用可回收的内存,它会给垃圾收集器带来额外的压力。

除非创建对象很昂贵,否则我不会打扰。

优点:

  • 创建的对象较少 – 如果对象创建很昂贵,这可能很重要。 (规范示例可能是数据库连接,其中“创建”包括与服务器建立网络连接,提供身份validation等)

缺点:

  • 更复杂的代码
  • 共享资源=锁定; 潜在的瓶颈
  • 违反GC对象生命周期的期望(大多数对象将是短期的)

你有一个实际的问题,你想解决,还是这种推测? 除非你有基准测试/配置文件显示存在问题,否则我不会考虑做这样的事情。

优化的第一定律:不要这样做。 第二定律:不要这样做,除非你真的已经测量并知道你需要优化的事实和地点。

只有当对象的创建成本非常高,并且它们实际上可以被重用时(你可以只用公共操作将状态重置为可以重用的东西),它就会有效。

你提到的两个好处并不是真的:java中的内存分配是免费的 (成本接近10个cpu指令,这没什么)。 因此,减少对象的创建只会节省您在构造函数中花费的时间。 这可以是一个非常重的对象,可以重用(数据库连接,线程)而不会改变:你重用相同的连接,相同的线程。

GC时间不会减少。 事实上,情况会更糟。 对于移动的世代GC(Java是或者高达1.5),GC运行的成本取决于活动对象的数量,而不是释放的内存。 活动对象将被移动到内存中的另一个空间(这使得内存分配如此之快:每个GC块内的空闲内存是连续的)在被标记为旧的并移入旧一代内存空间之前几次。

作为GC的编程语言和支持的设计考虑到了常见的用法。 如果您在许多情况下避开常见用法,最终可能会更难以阅读效率较低的代码。

池化意味着您通常不能使对象不可变。 这导致了defencive复制,所以你最终会制作比你刚制作一个新的不可变对象更多的副本。

不可变性并不总是令人满意,但往往你会发现事情是不可改变的。 使它们不是不可变的,以便您可以在池中重用它们可能不是一个好主意。

所以,除非你确定这是一个问题,否则不要打扰。 使代码清晰易懂,并且可能性足够快。 如果不是,那么代码清晰且易于遵循的事实将使其更容易加速(通常)。

别。

这是2001年的思考。 现在一天仍然有价值的唯一对象“池”是单身。 我仅使用单例来减少用于分析的对象创建(因此我可以更清楚地看到影响代码的是什么)。

你还有其他任何东西只是为了没有好处而破坏记忆。

继续并在创建1,000,000个对象时运行配置文件。 这是微不足道的。

这篇旧文章。

它完全取决于您创建对象的成本, 与您创建它们的次数相比 …例如,只是美化结构的对象(例如,只包含几个字段,除了访问器之外没有其他方法)是一个真正的汇集用例。

一个现实生活中的例子:我需要从生成大量整数/等级对的过程中重复提取n个排名最高的项(整数)。 我在有界优先级队列中使用了“pair”对象(一个整数和一个浮点排名值)。 重新使用这些对,而不是清空队列,抛弃它们并重新创建它们,产生了20%的性能提升……主要是在GC充电中,因为在JVM的整个生命周期中都不需要重新分配对。

对象池通常只是数据库连接等昂贵对象的好主意。 在Java 1.4.2之前,对象池可以提高性能,但是从Java 5.0对象池开始,除了帮助之外更可能损害性能,并且通常删除对象池以提高性能(和简单性)

我同意Jon Skeet的观点,如果你没有特定的理由来创建一个物体池,我不会打扰。

在某些情况下,游泳池确实非常有用/必要。 如果您有一个创建成本昂贵但可以重用的资源(例如数据库连接),那么使用池可能是有意义的。 此外,在数据库连接的情况下,池可用于防止您的应用程序打开与数据库的过多并发连接。