当前位置:网站首页>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接口
边栏推荐
- MySQL查询优化与调优
- 【Ryerson情感说话/歌唱视听数据集(RAVDESS) 】
- Significant differences between Oracle and Postgresql in PLSQL transaction rollback
- XSS相关知识点
- 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
- 如果禁用了安全启动,GNOME 就会发出警告
- 解决问题遇到的问题
- PL/SQL Some Advanced Fundamental
- How to drop all tables under database in MySQL
- 4-way two-way HDMI integrated business high-definition video optical transceiver 8-way HDMI high-definition video optical transceiver
猜你喜欢

Gigabit 2 X light 8 electricity management industrial Ethernet switches WEB management - a key Ring Ring net switch
SQL injection in #, - +, - % 20, % 23 is what mean?

Y86. Chapter iv Prometheus giant monitoring system and the actual combat, Prometheus storage (17)

【Ryerson情感说话/歌唱视听数据集(RAVDESS) 】

企业直播风起:目睹聚焦产品,微赞拥抱生态

仿牛客论坛项目梳理

软件测试如何系统规划学习呢?

自定义通用分页标签02

6口全千兆二层网管型工业以太网交换机千兆2光4电光纤自愈ERPS环网交换机
SQL注入中 #、 --+、 --%20、 %23是什么意思?
随机推荐
2003. 每棵子树内缺失的最小基因值 DFS
【源码】使用深度学习训练一个游戏
The general SQL injection flow (sample attached)
2千兆光+6千兆电导轨式网管型工业级以太网交换机支持X-Ring冗余环网一键环网交换机
案例 | 重庆银行流动数据安全挑战及应对实践
目标检测-中篇
sql注入一般流程(附例题)
6-port full Gigabit Layer 2 network managed industrial Ethernet switch Gigabit 2 optical 4 electrical fiber self-healing ERPS ring network switch
Enterprise live broadcast is on the rise: Witnessing focused products, micro-like embracing ecology
STM8S project creation (STVD creation) --- use COSMIC to create a C language project
pnpm 是凭什么对 npm 和 yarn 降维打击的
Implementing a server-side message active push solution based on SSE
移动端响应式适配的方法
千兆2光8电管理型工业以太网交换机WEB管理X-Ring一键环网交换机
Asynchronous programming solution Generator generator function, iterator iterator, async/await, Promise
自定义通用分页标签01
【Ryerson情感说话/歌唱视听数据集(RAVDESS) 】
机器学习之视频学习【更新】
马尔可夫链
db2中kettle报错 Field [XXX] is required and couldn‘t be found 解决方法