当前位置:网站首页>unity框架之缓存池
unity框架之缓存池
2022-08-04 03:47:00 【零一与黑白】
缓存池产生的原因:
- 1、当new一个对象后就会在内存中分配一定空间,用完后即使删除这个对象,内存中的空间也没有释放,只是断开了和这块空间的引用关系而已,所以内存占用量就会不断上升。
- 2、只有当内存占用量达到一定数量后触发垃圾回收机制才会把没用的内存释放掉,也就是触发了一次GC。触发GC需要进行大量的计算、验证之类的把那些没用的数据筛选出来,这样就会对CPU造成一定消耗,触发GC的时候很容易出现卡顿。
- 3、综上:为了解决这个问题,就需要减少new对象的次数,于是就诞生了缓存池的概念,我把一定数量的对象提前new出来放在缓存池里,这个数量一般是设置好的,在内存中的占用空间也是固定的,于是,每次需要对象的时候不再new对象了,而是去缓存池拿现有的对象。这样就避免了new对象而造成的内存空间不断减少,进而减少了触发GC的次数。
- 4、缓存适用于需要频繁创建销毁的对象。
缓存池介绍
结构
整体结构
缓存池部分
SpawnConifg的Inspector窗口编辑
接口 | 继承自接口的实体类 |
---|---|
IObjectPoo缓存池接口 | ComponentPoolOfQueue、ComponentPoolOfStack、ObjectPoolOfQueue、ObjectPoolOfStack、 |
SpwnItem实体类接口 | 这个就不写了 |
主要方法
类/接口 | 方法 | 属性 |
---|---|---|
Spawn.cs | 初始化(读取配置信息–>向缓存池添加对象)、取出对象、回收对象 | Dictionary<string, IObjectPool>类型的缓存池字典 |
IObjectPool | GetObject();取出对象、RecycleObject(T obj)回收对象 | |
PoolBuilder | 默认数量、父级Transform | |
ComponentPoolOfQueue | 三个构造方法(对象、固定数量的对象、对象数组、获取对象、回收对象 | 缓存的对象、对象栈、数量 |
SpwnItem | 这个就不写了 |
相关知识点
Srack栈:
类/接口 | 方法 |
---|---|
Push() | Push对象插入Stack的顶部(入栈操作) |
Pop() | 移除并返回Stack顶部的对象(出栈操作) |
Peek() | 返回位于Stack顶部的对象,但不移除 |
Contains() | 确定某元素是否存在Stack中 |
Clear() | 从Stack中移处所有元素 |
Count() | 获取Stack中包含的元素数量 |
ComponentPollOfStack.cs
孵化器:管理缓存池
1、管理继承于SpawnItem的对象缓存池,
2、产出继承于SpawnItem对象
3、回收继承于SpawnItem对象
/** //孵化器,用于产出继承于SpawnItem的对象 */
public static class Spawn{
private static Dictionary<string, IObjectPool<SpawnItem>> SpwanPools;
//孵化器初始化
[AutoLoad(1)]
private static void Initialize(){
SpawnItem.OnRecycleEvent += RecycleObject;
SpawnPools = new Dictionary<string, IObjectPool<SpawnItem>>();
SpawnConfig spawnConfig = Resources.Load<SpawnConfig>("ScriptableObject/SpawnConfig");
foreach(var item in spawnConfig.Spawns){
if(string.IsNullOrEmpty(item.Prefab.ItemName)){
Debug.LogErrorFormat("对象名不能为空!检查预制体 {0} 的ItemName属性", item.Prefab.name);
break;
}
else if(SpawnPools.ContainsKey(item.Prefab.ItemName){
Debug.LogErrorFormat("对象名冲突!无法重复创建!检查预制体 {0} 的ItemName属性", item.Prefab.name);
break;
}
else{
SpawnPools.Add(item.Prefab.ItemName, new ComponentPollOfStack<SpawnItem>(item.Count, item.Prefab));
}
}
}
//取出对象
public static T GetObject<T>(string name) where T : SpawnItem{
SpawnItem item = SpawnPools[name].GetObject();
item.IsAllowRecycle = true;
if(item is T){
return item as T;
} else {
return null;
}
}
//回收对象
private static void RecycleObject(SpawnItem symbol){
SpawnPools[symbol.ItemName].RecycleObject(symbol);
}
}
ComponentPollOfStack.cs
1、对象缓存池
2、ComponentPoolOfQueue、ObjectPoolOfQueue、ObjectPoolOfStack类似
/** //对象缓存池 */
public class ComponentPoolOfStack<T> : PoolBuilder, IObjectPool<T> where T :Component, new(){
//保存的对象
private T template;
//对象栈
protected Stack<T> Pool;
//栈长
public int Count {
get {
return Pool.Count;}}
//有参构造
public ComponentPoolOfStack(T obj){
template = obj;
Pool == new Stack<T>(MAXCOUNT);
for(int i=0; i < MAXCOUNT; i++){
T newObj = Object.Instantiate(template, Parent);
RecycleObject(newObj);
}
}
//有参构造
public ComponentPoolOfStack(int count, T obj){
template = obj;
MAXCOUNT = count;
Pool == new Stack<T>();
for(int i=0; i < MAXCOUNT; i++){
T newObj = Object.Instantiate(template, Parent);
RecycleObject(newObj);
}
}
//取出对象(出栈)
public T GetObject(){
T obj = null;
if(Pool.Count <= 0)
obj = Object.Instantiate(template, Parent);
else
obj = Pool.Pop();
obj.gameObject.SetActive(true);
return obj;
}
//回收对象(入栈)
public void RecycleObject(T obj){
if(Pool.Count >= MAXCOUNT){
Object.Destroy(obj,gameObject);
return;
}
obj.gameObject.SetActive(false);
obj.transform.SetParent(Parent);
obj.transform.localPosition = Vector3.zero;
obj.transform.rotation = Quaternion.identity;
Pool.Push(obj);
}
}
PoolBuilder.cs
声明一些缓存池需要的默认属性
public class PollBuilder{
protected int MAXCOUNT = 15;
private static Transform parent = null;
public static Transform Parent {
get {
return parent; } }
}
IOjectPool.cs
缓存池接口,声明了一些缓存池的方法
public interface IObjectPool<T>{
//取出对象(出栈)
T GetObject();
//回收对象(入栈)
void RecycleObject(T obj);
}
SpawnConfigEditor
管理SpawnConfig(ScriptableObject)的在窗口编辑中的数据问题
[CustomEditor(typeof(SpawnConfig))]
public class SpawnConfigEditor : Editor
{
private SpawnConfig spawn;
private void OnEnable(){
spawn = target as SpawnConfig;
}
public override void OnInspectorGUI(){
//实现Editor已经设置好的一些Inspector定义
base.OnInspectorGUI();
//获取一个按钮样式
GUIStyle style = GUI.skin.GetStyle("Button");
style.fontSize = 20;
//是否点击:按钮(按钮的文本,按钮的样式,高度(new一个高度))
//大致是读取Prefabs中的所有数据,然后将这些数据中SpawnItem类型的数据存入一个SpawnConfig类型的参数中,然后更新到ScriptableObject资源文件夹中
if (GUILayout.Button("更新Spawn列表", style, new[] {
GUILayout.Height(50)})){
List<SpawnItem> items = new List<SpawnItem>();
//路径
string root = Application.dalaPath + "/Prefabs";
//是否存在此路径
if (Directory.Exists(root)) {
//获取当前目录下的所有文件路径名(包括文件夹)
string[] paths = Directory.GetFiles(root, "*", SearchOption.AllDirectories);
for (int i = 0; i < paths.length; i++) {
//切割路径名
string path = path[i].Substring(paths[i].IndexOf("Assets"));
//IO:根据(路径名、泛型)加载数据
SpawnItem item = AssetDatabase.LoadAssetAtPath<SpawnItem>(path);
if (item != null) {
items.Add(item);
}
}
List<SpawnConfig.SpawnNode> nodes = new List<SpawnConfig.SpawnNode>(item.Count);
for (int i = 0; i < items.Count; i++) {
int count = 15;
for (int j = 0; i < spawn.Spawns.Count; j++){
if(spawn.Spawns[j].Prefab.ItemName.Equals(items[i].ItemName)){
count = spawn.Spawns[j].Count;
break;
}
}
SpawnConfig.SpawnNode node = new SpawnConfig.SpawnNode();
node.Prefab = items[i];
node.Count = count;
nodes.Add(node);
}
spawn.Spawns = nodes;
}
EditorUtility.SetDirty(spawn);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
style.fontSize = 12;
}
[MenuItem("Tools/CreateSpwanConfig")]
public static void CreateAudioConfig(){
string path = "Assets/Resources/ScriptableObject/SpawnConfig.asset";
string directory = Application.dataPath + "/Resources/ScriptableObject";
if(!File.Exists(path))
{
Directory.CreateDirectory(directory);
AssetDatabase.CreateAsset(ScriptableObject.CreateInstance<SpawnConfig(), path>);
AssetDatabase.Refresh();
}
else
{
#if UNITY_EDITOR
Debug.LogWarning("SpawnConfig已存在,不允许重复创建");
#endif
}
}
}
需要了解的API
using System
using UnityEditor
Editor接口
边栏推荐
- Senior PHP development case (1) : use MYSQL statement across the table query cannot export all records of the solution
- 【翻译】Terraform和Kubernetes的交集
- PL/SQL Some Advanced Fundamental
- Use serve to build a local server
- 《nlp入门+实战:第八章:使用Pytorch实现手写数字识别》
- 怎么把elastic中的异常登录ip和日志自动导出或抓取到数据库中?
- XSS related knowledge points
- 数据治理平台项目总结和分析
- Mockito单元测试
- 深度学习——以CNN服装图像分类为例,探讨怎样评价神经网络模型
猜你喜欢
Why use Selenium for automated testing
数组相关 内容 解析
拿捏JVM性能优化(自己笔记版本)
SQL注入中 #、 --+、 --%20、 %23是什么意思?
三分建设,七分管理!产品、系统、组织三管齐下节能降耗
6-port full Gigabit Layer 2 network managed industrial Ethernet switch Gigabit 2 optical 4 electrical fiber self-healing ERPS ring network switch
【源码】使用深度学习训练一个游戏
Shell 函数
Postgresql source code (66) insert on conflict grammar introduction and kernel execution process analysis
深度学习——以CNN服装图像分类为例,探讨怎样评价神经网络模型
随机推荐
自定义通用分页标签01
4-way two-way HDMI integrated business high-definition video optical transceiver 8-way HDMI high-definition video optical transceiver
基于 SSE 实现服务端消息主动推送解决方案
【医保科普】维护医保基金安全,我们可以这样做
Mockito单元测试
力扣(LeetCode)215. 数组中的第K个最大元素(2022.08.03)
MySQL query optimization and tuning
Polygon zkEVM network node
企业直播风起:目睹聚焦产品,微赞拥抱生态
Gigabit 2 X light 8 electricity management industrial Ethernet switches WEB management - a key Ring Ring net switch
学会iframe并用其解决跨域问题
STM8S105K4T6------Serial port sending and receiving
移动支付线上线下支付场景
Introduction to the memory model of the JVM
2022杭电多校联赛第五场 题解
如果禁用了安全启动,GNOME 就会发出警告
深度学习——以CNN服装图像分类为例,探讨怎样评价神经网络模型
外卖店优先级
十一种概率分布
XSS相关知识点