当前位置:网站首页>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接口
边栏推荐
猜你喜欢

Introduction to mq application scenarios

Hey, I had another fight with HR in the small group!

打造一份优雅的简历
![出现504怎么办?由于服务器更新导致的博客报504错误[详细记录]](/img/e0/32d78fac04dc2deb1cb1f847a7bab5.png)
出现504怎么办?由于服务器更新导致的博客报504错误[详细记录]

千兆2光8电管理型工业以太网交换机WEB管理X-Ring一键环网交换机

劝退背后。

DIY电工维修如何拆卸和安装开关面板插座

Significant differences between Oracle and Postgresql in PLSQL transaction rollback

MySQL查询优化与调优

new Date converts strings into date formats Compatible with IE, how ie8 converts strings into date formats through new Date, how to replace strings in js, and explain the replace() method in detail
随机推荐
MySQL query optimization and tuning
自定义通用分页标签01
sql语句查询String类型字段小于10的怎么查
【id类型和NSObject指针 ObjectIve-C中】
【观察】超聚变:首提“算网九阶”评估模型,共建开放繁荣的算力网络
SQL注入中 #、 --+、 --%20、 %23是什么意思?
Polygon zkEVM网络节点
Eight guiding principles to help businesses achieve digital transformation success
数据集类型转换—TFRecords文件
[Ryerson emotional speaking/singing audiovisual dataset (RAVDESS)]
2022 Hangzhou Electric Power Multi-School League Game 5 Solution
【Ryerson情感说话/歌唱视听数据集(RAVDESS) 】
高效IO模型
The video of machine learning to learn [update]
出现504怎么办?由于服务器更新导致的博客报504错误[详细记录]
仿牛客论坛项目梳理
A Preliminary Study of RSS Subscription to WeChat Official Account-feed43
LeetCode每日一题(2285. Maximum Total Importance of Roads)
深度学习——以CNN服装图像分类为例,探讨怎样评价神经网络模型
Metaverse "Drummer" Unity: Crazy expansion, suspense still exists