如何构建一个对象池并使用

1.背景

在项目中,如果频繁的通过new 创建对象,之后让gc再去回收,这就很容易造成内存抖动,并且频繁的GC本身也会消耗内存,这样就很容易在一瞬间造成OOM 内存溢出,因为瞬间申请大量内存会造成内存占用突然升高,如果GC 还没来的及回收,或者频繁GC,内存就会居高不下,这时有两种处理方式,一个是减少对象的创建,一个是复用对象。

2. 对象复用的基本原理

所谓对象复用,就是在对象创建使用完成后将对象内部的数据清除,然后将对象放到缓存中,等到下次需要创建新对象时拿出来复用,这样一来一回,只需要占用固定的内存就可以,不用每次都去new 一个对象申请内存,即避免的内存抖动,又避免了频繁GC,造成可能的稳定性问题,但是也有一个小弊端,就是这块缓存的对象所占的对象是固定的,无法随着GC来回收,如果需要回收需要我们手动处理,所以这个就需要我们对使用场景来评估。

3.如何构建一个对象池

1.需要有一个合适的对象

2.定一个对象池的大小

3.处理对象的回收

4.在核实的位置获取对象池中数据并且在使用完成后回收

4. 构建一个对象池

复制代码
public class MapCache extends HashMap<String, String> {
    private static final String TAG = "MapCache";
    //下一条对象
    MapCache next;
    public static final Object sPoolSync = new Object ();
    // 链表首个对象
    private static MapCache sPool;
    //当前链表个数
    private static int sPoolSize = 0;
    //可缓存的最大空闲对象数量,超出后将开始new 对象,由GC 处理回收
    private static final int MAX_POOL_SIZE = 50;

    @Override
    public void clear() {
       recycle ();
    }

    /**
     * 获取map对像,如果对象池存在空闲对象,就从头部取出一个空对象返回
     * 否则new 一个新对象。
     */
    public static MapCache obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                MapCache m = sPool;
                sPool = m.next;
                m.next = null;
                sPoolSize--;
                // 返回链表头部对象
                return m;
            }
        }
        return new MapCache ();
    }

    /**
     * 回收对象资源
     */
    private void recycle() {
        super.clear ();
        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                // 将当前消息放到链表头部
                sPool = this;
                //链表消息池对象增加1
                sPoolSize++;
            }
        }
    }
 
}

其实还算简单,基本原理就是定一个对象池大小,用一个链表来存储对象,然后定义一个静态的头部对象sPoolSync,然后定义这个头部对象的next 指向的下一个对象,这样就形成了一个链表的对象池。

3.1 获取对象

当通过obtain() 方法来获取一个对象时,如果链表中有缓存的对象数据就取出链表首部的对象,然后将他的下一个对象指向头部对象,然后将对象池减一个,如果没有足够的对象或者首次调用,那就new 一个对象返回。

3.2 对象的回收

对象内容的回收recycle()需要根据不同的对象定义来处理,就比如我这定义的HashMap,使用完成后只需要调用clear 方法将原数据清空,然后将这个对象加入到线程池中即可。

具体操作 就是先将当前的链表头部对象指向当前的空闲对像的next,然后将空闲该对象 指向头部静态对像,然后对象池加一,这样就顺利将空闲对像加到链表头部。

相关推荐
鹿角片ljp27 分钟前
KV Cache 解析
java·算法
captain37642 分钟前
网络原理(9)-数据链路层
java·网络协议·java-ee
惊讶的猫1 小时前
意图识别置信度和检索重排的分数
java
2601_966949651 小时前
只拿到股票代码还不够:量化程序到底还需要哪些标的信息?——从数据建模开始理解股票元数据
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
caoerzhong2 小时前
仓库管理数字化趋势解读:JeeWMS 开源 Java WMS 视角下的五个演进方向
java·开源
m0_734571762 小时前
深入理解5g <十八>传输块tbsize的计算
开发语言·5g
程序员JerrySUN2 小时前
Jetson Edge AI 实战01:Nano、Xavier、Orin 怎么选?Jetson 硬件选型详解【视频讲解】
java·数据库·redis·安全·mybatis
Joy T3 小时前
Spring AI 2.0 Agent 进阶:Memory、State 与 Context Engineering 常见技术全景
java·人工智能·后端·spring·agent入门·agent state
估值探索者3 小时前
【Python量化系统工程化 #08】关了 SSH 就停?systemd 让脚本开机自启 + 异常自动拉起
java·c++·人工智能·分类·数据挖掘