专栏首页技术小黑屋关于对象池的一些分析

关于对象池的一些分析

在日常的开发工作中,我们可能使用或者听说过对象池,线程池以及连接池。本文将介绍对象池的产生缘由,具体实现细节,以及需要注意的问题。

什么是对象池(模式)

  • 对象池(模式)是一种创建型设计模式
  • 它持有一个初始化好的对象的集合,将对象提供给调用者。

对象池的目的

  • 减少频繁创建和销毁对象带来的成本,实现对象的缓存和复用

什么条件下使用对象池

  • 创建对象的成本比较大,并且创建比较频繁。比如线程的创建代价比较大,于是就有了常用的线程池。

对象池的例子

Android中使用对象池的应用有很多,比如下面的这些都是应用了该模式

  • Handler处理的Message
  • 线程池执行器ThreadPoolExecutor
  • 控件TabLayout
  • 控制TypedArray的Resources

以一个简单的获取SytledAttributions代码为例,展示一下对象池的应用

1 2 3 4 5 6 7 8 9 10 11

// Text colors/sizes come from the text appearance first final TypedArray ta = context.obtainStyledAttributes(mTabTextAppearance, android.support.v7.appcompat.R.styleable.TextAppearance); try { mTabTextSize = ta.getDimensionPixelSize( android.support.v7.appcompat.R.styleable.TextAppearance_android_textSize, 0); mTabTextColors = ta.getColorStateList( android.support.v7.appcompat.R.styleable.TextAppearance_android_textColor); } finally { ta.recycle(); }

想必这段代码都可能写过,那就是在一开始的时候,我们都会被告诫:使用TypedArray结束的时候,一定要调用它的recycle方法。

回想起来,当时自己还很疑惑为什么要这么规定,其实很简单,它使用了对象池。

调用者通过obtain方法从对象池中获取对象,然后使用完毕后,需要使用recycle方法返还给对象池。

三种角色

上面的介绍中,也或多或少提到了下面的三种角色

  • Reusable 可重用的对象
  • Client 调用者
  • ReusablePool 可重用的对象的池

Reusable

  • 创建的成本较大,比如线程或者数据库连接
  • 被ReusablePool持有
  • 被Client消费使用,使用完成应该被返回到ReusablePool

ReusablePool

  • 维护一定数量的Reusable,提供给客户端使用
  • 提供aquire或者obtain等方法,便于客户端请求Reusable
  • 提供recycle或者release等方法,便于客户端使用完毕后,将Reusable对象奉还。

Client

  • 请求ReusablePool或者Reusable对象
  • 使用完毕Reusable对象后,返回给ReusablePool

对象池无可用的对象时,再次对象请求,可能的表现行为

  • 如果池的大小可以增长,创建新的对象并返回给client
  • 阻塞client调用,直到有可用的对象回收并返回
  • 抛出异常,通知client
  • 返回null给client

同步处理

在多线程的环境下,我们也会使用对象池。因此做好必要的同步是必须的。

要进行同步处理的通常是这两个方法

  • aquire或obtain 负责返回对象
  • release或recycle 负责回收对象

下面是一段进行同步处理了的对象池的源码。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

public static class SynchronizedPool<T> extends SimplePool<T> { private final Object mLock = new Object(); /** * Creates a new instance. * * @param maxPoolSize The max pool size. * * @throws IllegalArgumentException If the max pool size is less than zero. */ public SynchronizedPool(int maxPoolSize) { super(maxPoolSize); } @Override public T acquire() { synchronized (mLock) { return super.acquire(); } } @Override public boolean release(T element) { synchronized (mLock) { return super.release(element); } } }

上述代码为Android中android.support.v4.util提供的Pools中的SynchronizedPool的实现,它使用了synchronized关键字实现同步问题。

对象池与单例模式

为了统一管理对象,建议将对象池设为单例。

应用单例模式的时候,需要确保在多线程并发的情况下保持唯一的实例创建,具体实现方案,可以参考单例这种设计模式

池的大小选择

  • 通常情况下,我们需要控制对象池的大小
  • 如果对象池没有限制,可能导致对象池持有过多的闲置对象,增加内存的占用
  • 如果对象池闲置过小,没有可用的对象时,会造成之前对象池无可用的对象时,再次请求出现的问题
  • 对象池的大小选取应该结合具体的使用场景,结合数据(触发池中无可用对象的频率)分析来确定。

空间换时间的折中

  • 本质上,对象池属于空间换时间的折中
  • 它通过缓存初始化好的对象来提升调用者请求对象的响应速度。
  • 除此之外,折中(tradeoff)是软件开发中的一个重要的概念,会贯穿整个软件开发过程中。

对象池好处

  • 提升了client获取对象的响应速度,比如单个线程和资源连接的创建成本都比较大。
  • 一定程度上减少了GC的压力。
  • 对于实时性要求较高的程序有很大的帮助

对象池弊端

脏对象的问题

所谓的脏对象就是指的是当对象被放回对象池后,还保留着刚刚被客户端调用时生成的数据。

脏对象可能带来两个问题

  • 脏对象持有上次使用的引用,导致内存泄漏等问题。
  • 脏对象如果下一次使用时没有做清理,可能影响程序的处理数据。

生命周期的问题

处于对象池中的对象生命周期要比普通的对象要长久。维持大量的对象也是比较占用内存空间的。

以ThreadPoolExecutor为例,它提供了allowCoreThreadTimeOutsetKeepAliveTime两种方法,可以在超时后销毁核心线程。我们在具体的实践中可以参考这个策略。

异常处理问题

相对来说,使用对象池client调用也会复杂一些,比如请求对象时有可能出现的阻塞,异常或者null值。这些都需要我们做一些额外的处理,来确保程序的正常运行。

除此之外,还有上面的提到的两个问题,他们分别是

  • 同步问题
  • 池大小设置问题

所以当我们想要使用对象池时,需要谨慎的衡量并准确的实现,享受它带来的好处,并避免其带来的问题。

参考文章

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 垃圾回收器如何处理循环引用

    垃圾回收是一门编程语言中必不可少的一部分,不论是手动释放内存的C和C++,还是自动回收垃圾的Java和C#等语言。对于Java这样的语言,一般的开发者不强求关心...

    技术小黑屋
  • 译文:理解Java中的弱引用

    不久之前,我面试了一些求职Java高级开发工程师的应聘者。我常常会面试他们说,“你能给我介绍一些Java中得弱引用吗?”,如果面试者这样说,“嗯,是不是垃圾回收...

    技术小黑屋
  • 系统剖析Android中的内存泄漏

    作为Android开发人员,我们或多或少都听说过内存泄漏。那么何为内存泄漏,Android中的内存泄漏又是什么样子的呢,本文将简单概括的进行一些总结。

    技术小黑屋
  • 《Objective C编程》笔记

    1.为什么main()总是返回0?可以将main()的返回结果视为“粗欧文报告”,这样0就是好消息,没有错误就是成功。 2.消息:消息发送(指令)必须写在一对...

    nimomeng
  • 经典面试题-列举JSP的内置对象,同一应用中页面有哪些方法

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

    cwl_java
  • python传参是传值还是传引用

    在此之前先来看看变量和对象的关系:Python 中一切皆为对象,数字是对象,列表是对象,函数也是对象,任何东西都是对象。而变量是对象的一个引用(又称为名字或者标...

    用户1679793
  • 《JavaScript 模式》读书笔记(1)— 简介

      广义上的模式是指“重现事件或者对象的主题,……它是一个可以用来产生其他事物的模版或者模型”。在软件开发过程中,模式是指一个通用问题的解决方案。一个模式不仅仅...

    zaking
  • HotSpot 图解年轻代回收

    实际上,只是用对象的对象头去把对象连接起来(这里说的对象都是 C++ 层面对象的具体实现,也就是 oopDesc 的对象 在内存中占用的一段内存块)

    执生
  • 《Head First 设计模式》笔记

    软件开发的一个不变真理:不管当初软件设计得多好,一段时间后,总是需要成长与改变,否则软件就会“死亡”。

    谛听
  • GOF设计模式快速学习

    这段时间,学习状态比较一般,空闲时基本都在打游戏,和研究如何打好游戏,终于通过戏命师烬制霸LOL,玩笑了。为了和"学习"之间的友谊小船不翻,决定对以往学习过的G...

    用户1216676

扫码关注云+社区

领取腾讯云代金券