unity框架之缓存池

缓存池产生的原因:

  • 1、当new一个对象后就会在内存中分配一定空间,用完后即使删除这个对象,内存中的空间也没有释放,只是断开了和这块空间的引用关系而已,所以内存占用量就会不断上升。
  • 2、只有当内存占用量达到一定数量后触发垃圾回收机制才会把没用的内存释放掉,也就是触发了一次GC。触发GC需要进行大量的计算、验证之类的把那些没用的数据筛选出来,这样就会对CPU造成一定消耗,触发GC的时候很容易出现卡顿。
  • 3、综上:为了解决这个问题,就需要减少new对象的次数,于是就诞生了缓存池的概念,我把一定数量的对象提前new出来放在缓存池里,这个数量一般是设置好的,在内存中的占用空间也是固定的,于是,每次需要对象的时候不再new对象了,而是去缓存池拿现有的对象。这样就避免了new对象而造成的内存空间不断减少,进而减少了触发GC的次数。
  • 4、缓存适用于需要频繁创建销毁的对象。

缓存池介绍

结构

整体结构
取出对象,回收对象
读取
增加,减少
外界调用
Spawn孵化器
IObjectPool缓存池接口
unity中的配置信息SpawnConfig
缓存池部分
继承
缓存
缓存
继承使用变量
SpawnItem实体类
音频实体类
IObjectPool缓存池接口
具体缓存池: ComponentPoolOfQueue,ComponentPoolOfStack,ObjectPoolOfQueue,ObjectPoolOfStack
PoolBuilder声明默认属性
SpawnConifg的Inspector窗口编辑
读取
编辑Inspector
SpawnConfigEditor
SpawnConfig.cs
unity中的配置信息SpawnConfig
接口继承自接口的实体类
IObjectPoo缓存池接口ComponentPoolOfQueue、ComponentPoolOfStack、ObjectPoolOfQueue、ObjectPoolOfStack、
SpwnItem实体类接口这个就不写了

主要方法

类/接口方法属性
Spawn.cs初始化(读取配置信息–>向缓存池添加对象)、取出对象、回收对象Dictionary<string, IObjectPool>类型的缓存池字典
IObjectPoolGetObject();取出对象、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接口
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值