当前位置: 首页 > news >正文

03.缓存池

一、C#的内存回收机制

实例化对象时,会在内存中分配空间,删除对象时,只是断开了该对象对内存空间的引用,实际上内存还是被占用的。当我们需要内存时,仍会不断分配内存空间,直到内存中无处可用,才会触发GC。

二、缓存池

1、什么是缓存池

缓存池(Object Pool,对象池)是一种内存 / 对象管理设计模式,核心是提前创建一批常用、创建 / 销毁成本高的对象(如游戏中的子弹、敌人,或程序中的网络连接、线程),将其存入一个 “池” 中;当需要使用时直接从池里获取,使用完毕后不销毁,而是放回池中供后续复用,避免频繁创建和销毁对象的开销。

2、缓存池的作用

  1. 降低性能开销
    频繁创建 / 销毁对象(尤其是复杂对象,如包含大量组件的游戏物体、需要初始化资源的网络连接)会触发频繁的内存分配与回收(如 Unity 中的 GC 垃圾回收),导致性能波动(如游戏卡顿)。缓存池通过 “复用对象” 减少创建 / 销毁操作,显著降低内存碎片和 GC 压力。

  2. 稳定程序运行效率
    避免 “峰值性能消耗”:例如游戏中瞬间生成大量子弹时,若每次都 new 创建,会导致短时间内性能骤降;而从缓存池直接取对象,能保持性能稳定,响应更快。

  3. 统一管理对象生命周期
    缓存池集中管理对象的 “创建、复用、回收”,可统一控制对象的初始化状态(如重置子弹位置、清空数据),避免对象状态混乱;同时便于监控对象数量,防止资源泄漏或过度占用内存(如设置池的最大容量)。

3、典型应用场景

        游戏开发:子弹、敌人、特效、UI 弹窗等高频创建 / 销毁的对象;
网络编程:数据库连接池、HTTP 连接池(复用连接,避免频繁建立 TCP 连接);
多线程:线程池(复用线程,避免频繁创建线程的系统开销)。

三、实现一个基础的缓存池

using System.Collections;
using System.Collections.Generic;
using UnityEngine;/// <summary>
/// 缓存池模块
/// </summary>
public class PoolMgr :BaseManager<PoolMgr>
{//缓存池容器public Dictionary<string, List<GameObject>> poolDic = new Dictionary<string, List<GameObject>>();/// <summary>/// 往外拿东西,出池子/// </summary>/// <param name="name"></param>/// <returns></returns>public GameObject GetObj(string name){GameObject obj = null;if (poolDic.ContainsKey(name) && poolDic[name].Count > 0)//有抽屉,抽屉里还有东西{obj = poolDic[name][0];poolDic[name].RemoveAt(0);}else{obj = GameObject.Instantiate(Resources.Load<GameObject>(name));obj.name = name;//把对象名字改成和池子一样的名字}obj.SetActive(true);return obj;}/// <summary>/// 还回暂时不用的东西,进池子/// </summary>public void PushObj(string name,GameObject obj){obj.SetActive(false);if(poolDic.ContainsKey (name))//有抽屉{poolDic[name].Add(obj);}else{poolDic.Add (name,new List<GameObject>{ obj});}}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class DelayPush : MonoBehaviour
{// Start is called before the first frame updatevoid OnEnable(){Invoke("Push", 1);}public void Push(){PoolMgr.GetInstance().PushObj(this.gameObject.name, this.gameObject);}
}

测试脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Test2 : MonoBehaviour
{void Update(){if(Input.GetMouseButtonDown (0)){PoolMgr.GetInstance().GetObj("Cube");}if (Input.GetMouseButtonDown(1)){PoolMgr.GetInstance().GetObj("Sphere");}}
}

四、优化缓存池

由于三中的方法创建出的对象会直接暴露在层级窗口中,会显得没有条理,进行缓存池优化。

1、设置父对象。

2、清空缓存池。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;/// <summary>
/// 池子中的一列容器
/// </summary>
public class PoolData
{public GameObject fatherObj;//抽屉中对象的父节点public List<GameObject> poolList;//对象的容器public PoolData(GameObject obj,GameObject poolObj){//给抽屉创建父对象,这个父对象是衣柜的子对象fatherObj = new GameObject(obj.name);fatherObj.transform.parent = obj.transform;poolList = new List<GameObject>() {};PushObj(obj);}public void PushObj(GameObject obj){poolList.Add(obj);obj.transform.parent = fatherObj.transform;obj.SetActive(false);}public GameObject GetObj(){GameObject obj = null;obj = poolList[0];poolList.RemoveAt(0);obj.SetActive(true);obj.transform.parent = null;//断开父子关系return obj;}
}/// <summary>
/// 缓存池模块
/// </summary>
public class PoolMgr :BaseManager<PoolMgr>
{//缓存池容器public Dictionary<string, PoolData> poolDic = new Dictionary<string, PoolData>();private GameObject poolObj;/// <summary>/// 往外拿东西,出池子/// </summary>/// <param name="name"></param>/// <returns></returns>public GameObject GetObj(string name){GameObject obj = null;if (poolDic.ContainsKey(name) && poolDic[name].poolList. Count > 0)//有抽屉,抽屉里还有东西{obj = poolDic[name].GetObj();}else{obj = GameObject.Instantiate(Resources.Load<GameObject>(name));obj.name = name;//把对象名字改成和池子一样的名字}obj.SetActive(true);obj.transform.parent = null;//断开父子关系return obj;}/// <summary>/// 还回暂时不用的东西,进池子/// </summary>public void PushObj(string name,GameObject obj){if (poolObj == null)poolObj = new GameObject("Pool");obj.transform.parent = poolObj.transform;//设置父对象为根节点obj.SetActive(false);if(poolDic.ContainsKey (name))//有抽屉{poolDic[name].PushObj(obj);}else{poolDic.Add (name,new PoolData(obj,poolObj));}}public void Clear(){//防止过场景移除后会出现错误//过场景时poolObj会被移除,但内存上还存在引用,此时就会发生错误poolDic.Clear();poolObj = null;}
}


文章转载自:

http://7jPBUStt.qcfgd.cn
http://5Kp7VpsN.qcfgd.cn
http://mT0w8zrZ.qcfgd.cn
http://Kz8VCamR.qcfgd.cn
http://ZxjQC20F.qcfgd.cn
http://59bOPvgM.qcfgd.cn
http://xP6mwgUR.qcfgd.cn
http://Odr6pa9o.qcfgd.cn
http://vGE4aKSZ.qcfgd.cn
http://abswXhLW.qcfgd.cn
http://EeBVpMDE.qcfgd.cn
http://nlDgLCAO.qcfgd.cn
http://zKSYsYSN.qcfgd.cn
http://gxvVwx3B.qcfgd.cn
http://0crBVXzP.qcfgd.cn
http://gDmBIGCC.qcfgd.cn
http://XUPy8KQI.qcfgd.cn
http://zLaeSOIu.qcfgd.cn
http://JqKGpJRW.qcfgd.cn
http://pUGv4MKJ.qcfgd.cn
http://NFw7Le4p.qcfgd.cn
http://RzZJxgC7.qcfgd.cn
http://z8Y7SatK.qcfgd.cn
http://yEBjveQr.qcfgd.cn
http://GF9NHsB0.qcfgd.cn
http://DPVq6X0U.qcfgd.cn
http://f4uZXtiF.qcfgd.cn
http://WTGUZOAt.qcfgd.cn
http://oF1ubCvT.qcfgd.cn
http://pDGobQPQ.qcfgd.cn
http://www.dtcms.com/a/369793.html

相关文章:

  • 突破反爬限制:动态IP轮换策略与实现
  • stunnel实现TCP双向认证加密
  • C#实现导入CSV数据到List<T>的完整教程
  • 安卓学习 之 按钮点击事件
  • Nmap网络扫描工具详细使用教程
  • 持续集成和持续交付 (CI/CD) 工具——Jenkins
  • 微信小程序携带token跳转h5, h5再返回微信小程序
  • ISO/IEC 27001 第八章 运行
  • 苍穹外卖项目实战(day-5完整版)-记录实战教程及问题的解决方法
  • GO语言的主要语法和特性
  • ubuntu 系統使用過程中黑屏問題分析
  • JavaScript 入门精要:从变量到对象,构建稳固基础
  • Go语言设计模式(三)抽象工厂模式
  • SDRAM-08 数据手册解读
  • [光学原理与应用-436]:晶体光学 - 各向同性与各向异性是描述材料物理性质随方向变化特性
  • python:如何生成 TA-Lib .whl 安装包?
  • AD渗透中服务账号相关攻击手法总结(Kerberoasting、委派)
  • 从Java全栈到Vue3实战:一次真实面试中的技术探索
  • python graphviz中文测试
  • 【VoNR】VoNR 不等于 VoLTE on 5G
  • 基于 GEE 批量下载 Landsat8 地表温度(LST)数据
  • 从“下山”到AI引擎:全面理解梯度下降(下)
  • Linux应用(2)——标准/目录IO
  • 问题三ai思路
  • 玳瑁的嵌入式日记D33-0905(IO多路复用)
  • GigaDevice(兆易创新)GD25Q64CSJGR 64Mbit FLASH
  • FEMDRW032G-88A19江波龙,工业级宽温EMMC存储FEMDRW032G采用eMMC5.1协议,具备32GB存储容量提供方案
  • Interior AI-AI驱动的室内设计工具
  • 裸机程序(3)
  • ai连接怡和达进行非标选型 抓包失败