简介
我们都有听过单例模式,即通过控制对象的创建(构造函数私有化)将对象的个数限制为1个。实际场景下,单例的场景毕竟是有限的。
在java程序中,要提高应用的性能,有以下两类情形
- 大量、频繁创建和回收的对象。如果这些对象的生命周期都很短暂,会导致频繁YoungGC;如果生命周期很长,会导致大量Full GC。gc过程会影响java程序的性能。
- 一些创建起来较为耗时的对象,比如线程和连接
所以最好的办法是,我们一开始创建一定数量的对象,然后复用这些对象。
资源限制也是一种保护策略,比如数据库链接池。除去这些对象本身的开销外,他们对外部系统也会造成压力,比如大量创建连接对DB也是有压力的。池化除了优化资源以外,本身限制了资源数,对外部系统也起到了一层保护作用。
对象池
内存是byte[]
级的复用,对象池是对象级的内存复用。对象池就相当于内存管理器,只不过内存分配和回收的级别是对象。
享元模式,另一种池技术
在对象池中,对象的实例个数往往是由程序人员根据应用负载做调整。
假设有一个考试信息类TestInfo
class{
String id;// 报名人员id
String location;// 考场
String subject; // 考试科目
}
这其中,location和subject的组合是有限的,因为我们可以将TestInfo信息分为共享信息(比如location和subject)和非共享信息(比如id)。对象池对外提供服务的接口变为pool.get(String key)
,key由location和subject组成,这样对象池中对象实例的个数与key的可能值构成线性关系。
连接池
netty 中涉及到了 线程池管理、连接池管理 以及 如何将这类操作 异步化。当然,一些略复杂,我们从 c3p0 中应该可以学习到,连接池管理 等
线程池
内存池/内存管理
池化的粒度
可以直接对资源池化,比如Socket/Thread(Java语言自带的线程池),也可以对资源封装过的对象进行池化,比如
- Jedis 对Socket 封装了Redis通信协议,然后JedisPool 对Jedis 进行池化 Jedis源码分析
- EventLoop 对Thread 进行封装,然后EventLoopGroup 对 EventLoop 进行池化
对象池矿建
异步对象池