对象池简述

在进行平时的功能开发时,对象池是一个比较常见的工具,用来减少GC的性能消耗,个人总结下来,对象池的关键有如下几点

- 管理使用中元素的集合,可以使是List
- 回收元素的集合,即池子本身,可以是Queue
- 得到元素的方法
- 回收元素的方法
- 回收所有元素的方法
- 按照需求,可以给池子来个最大数量
- 按照需求,可以来个初始化数量
- 对象池创建的是肉体,数据才是灵魂
- 对象池中的元素使用完之后,或者重复使用前,确保上面的旧数据已经清理完毕

1. 一个例子

csharp 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class ObjectPool<T> where T : Component
{
    [SerializeField]
    protected T Obj;
    
    /// <summary>
    /// 初始化数量
    /// </summary>
    protected int initalSize = 10;
    
    /// <summary>
    /// 最大数量
    /// </summary>
    protected int maxSize = 50;
    
    /// <summary>
    /// 池本身
    /// </summary>
    protected Queue<T> recycleQueue = new Queue<T>();
    
    /// <summary>
    /// 正在使用的元素集合
    /// </summary>
    protected List<T> usingList = new List<T>();
    
    /// <summary>
    /// 池结点
    /// </summary>
    protected Transform poolContainer;
    
    /// <summary>
    /// 得到的回调
    /// </summary>
    public Action<T> GetCallback;  
    
    /// <summary>
    /// 回收回调
    /// </summary>
    public Action<T> RecycleCallback;
    
    

    protected void InitPool()
    {
        for (int i = 0; i < initalSize; i++)
        {
            CreateNewObj();
        }
    }
    
    /// <summary>
    /// 创建新对象
    /// </summary>
    /// <param name="active"></param>
    /// <returns></returns>
    protected virtual T CreateNewObj(bool active = false)
    {
        if (recycleQueue.Count == maxSize)
        {
            return null;
        }
        
        var obj = GameObject.Instantiate(Obj, poolContainer);
        obj.gameObject.SetActive(active);

        if (active)
        {
            usingList.Add(obj);
        }
        else
        {
            recycleQueue.Enqueue(obj);
        }
        
        return obj;
    }
    
    /// <summary>
    /// 从池中得到对象
    /// </summary>
    /// <returns></returns>
    public virtual T Get()
    {
        T obj = null;
        if (recycleQueue.Count == 0)
        {
            obj = CreateNewObj();
            usingList.Add(obj);
        }

        if (recycleQueue.Count > 0)
        {
            obj = recycleQueue.Dequeue();
            obj.gameObject.SetActive(true);
            usingList.Add(obj);
        }
        
        GetCallback?.Invoke(obj);
        return obj;
    }
    
    
    public void Recycle(T obj)
    {
        if (recycleQueue.Count < maxSize)
        {
            recycleQueue.Enqueue(obj);
            usingList.Remove(obj);
            obj.gameObject.SetActive(false);
            obj.transform.SetParent(poolContainer);
        }
        
        RecycleCallback?.Invoke(obj);
    }
    
    /// <summary>
    /// 回收所有
    /// </summary>
    public void RecycleAll()
    {
        foreach (var obj in usingList.ToArray())
        {
            Recycle(obj);
        }
    }
}

2. 注意事项

即标红的这两点,个人认为是在使用对象池中最重要的地方,在上文中,使用了一个RecycleCallback回调,来模拟数据回收的回调,实际在使用时可能会调用元素自身的一个回收方法

比如


这样就确保了,元素在回收回对象池时,是"干净"的,那么下次再从池中取得元素就可以正常使用,否则会有残留数据影响。比如旧的元素上可能会注册一些事件,但是因为没有清除数据,所以再次使用时,因为元素本身只是回收进对象池,没有销毁,所以还是会触发旧的注册的事件

相关推荐
典典分享指南11 分钟前
短视频分镜提示词:让 AI 出片的产品口播
java·c#·bash·composer·symfony
Z5998178411 小时前
c#软件开发学习笔记--WPF(Canvas、数据绑定、MVVM模式、值转换器)
笔记·学习·c#
zhchyun20082 小时前
# 【Unity UI 进阶】仿 Element UI 打造企业级 Unity UI 组件库(06)
ui·unity·游戏引擎
淡海水3 小时前
05-03-栈队列-PriorityQueue-TElement-TPriority-NET6优先队列语义与四叉堆实现
服务器·前端·c#·priorityqueue·clr·telement
Behaviour8 小时前
Unity游戏HybridCLR 热更新接入实战
游戏·unity·游戏引擎
leonkay16 小时前
C# 特性(Attribute)——【1】基础讲解
开发语言·青少年编程·面试·c#·.net·个人开发
CSDN_RTKLIB17 小时前
数据库七大符号表
c#
leonkay17 小时前
C# 特性(Attribute)——【2】工业设备参数框架设计
经验分享·面试·架构·c#·学习方法·设计
2501_9065651218 小时前
小创 · 智能助手
开发语言·c#
LONGZETECH21 小时前
新能源汽车动力电池实训教学痛点与虚拟仿真技术解决方案
c语言·3d·unity·架构·汽车·汽车教学软件