Unity3D游戏的内存控制详解
前言
Unity3D是一款流行的游戏引擎,支持多种平台,包括PC、移动设备和VR等。随着游戏的复杂性不断提高,Unity3D的内存管理变得尤为重要。本文将详细介绍Unity3D游戏中的内存控制技术,包括自动内存管理、对象池、延迟加载资源和手动清理资源等方面,并提供相应的代码实现。
对惹,这里有一个游戏开发交流小组,希望大家可以点击进来一起交流一下开发经验呀!
一、Unity的自动内存管理
Unity提供了一些自动内存管理操作,主要集中在托管堆的管理上。当一个对象、字符串或数组被创建时,计算机会在堆中为其分配内存;当它们不再使用时,内存会被回收。Unity的Mono和C#的CLR负责自动内存管理,但开发者仍需遵循一些规范来优化内存使用。
- 值类型和引用类型
- 值类型:一般占用较少的字节数,传递时直接复制,成本较低。
- 引用类型:如字符串、数组等,直接复制效率非常低,因此在堆中存储,通过指针访问。
- 分配和垃圾收集
- 内存管理器跟踪未使用的堆区域,当实例化对象时,选择一个未使用的内存区域分配内存。
- 当已使用的内存不足时,垃圾收集器(GC)会查找不再被引用的内存块并释放它们。
- GC操作会暂停游戏运行,可能导致游戏延迟,称为GC峰值。
二、优化内存管理的技术
- 对象池
对象池是一种重用已创建对象的技术,可以减少内存分配和垃圾回收的次数。以子弹对象为例:
| public class BulletPool : MonoBehaviour | |
| { | |
| public GameObject bulletPrefab; // 子弹预制体 | |
| public int poolSize = 10; // 对象池大小 | |
| private List<GameObject> bullets; // 存储子弹对象的列表 | |
| private void Start() | |
| { | |
| bullets = new List<GameObject>(); // 初始化子弹列表 | |
| for (int i = 0; i < poolSize; i++) | |
| { | |
| GameObject bullet = Instantiate(bulletPrefab); // 实例化子弹对象 | |
| bullet.SetActive(false); // 将子弹对象禁用 | |
| bullets.Add(bullet); // 将子弹对象添加到列表中 | |
| } | |
| } | |
| public GameObject GetBullet() | |
| { | |
| foreach (GameObject bullet in bullets) | |
| { | |
| if (!bullet.activeInHierarchy) | |
| { | |
| bullet.SetActive(true); | |
| return bullet; | |
| } | |
| } | |
| // 如果没有可用的子弹对象,则创建一个新的子弹对象并添加到对象池中 | |
| GameObject newBullet = Instantiate(bulletPrefab); | |
| bullets.Add(newBullet); | |
| return newBullet; | |
| } | |
| } |
- 延迟加载资源
延迟加载资源可以减少游戏启动时的内存消耗。例如,在玩家按下空格键时加载关卡地图:
| public class LevelManager : MonoBehaviour | |
| { | |
| private bool isLevelLoaded = false; // 关卡是否已加载 | |
| private GameObject levelMap; // 关卡地图对象 | |
| private void Update() | |
| { | |
| if (!isLevelLoaded && Input.GetKeyDown(KeyCode.Space)) | |
| { | |
| LoadLevel(); | |
| } | |
| } | |
| private void LoadLevel() | |
| { | |
| levelMap = Instantiate(Resources.Load<GameObject>("LevelMap")); // 延迟加载关卡地图资源 | |
| isLevelLoaded = true; | |
| } | |
| } |
- 手动清理资源
手动清理不再使用的资源可以避免内存泄漏。例如,检测玩家按下“C”键后清理未使用的游戏对象和纹理资源:
| public class ResourceManager : MonoBehaviour | |
| { | |
| private List<GameObject> unusedObjects; // 存储未使用的游戏对象 | |
| private List<Texture2D> unusedTextures; // 存储未使用的纹理 | |
| private void Update() | |
| { | |
| if (Input.GetKeyDown(KeyCode.C)) | |
| { | |
| ClearUnusedResources(); | |
| } | |
| } | |
| private void ClearUnusedResources() | |
| { | |
| unusedObjects = new List<GameObject>(FindObjectsOfType<GameObject>()); // 获取场景中所有的游戏对象 | |
| unusedTextures = new List<Texture2D>(Resources.FindObjectsOfTypeAll<Texture2D>()); // 获取所有的纹理资源 | |
| foreach (GameObject obj in unusedObjects) | |
| { | |
| if (obj == null) | |
| { | |
| unusedObjects.Remove(obj); | |
| } | |
| else | |
| { | |
| Destroy(obj); // 销毁无效的游戏对象 | |
| } | |
| } | |
| foreach (Texture2D tex in unusedTextures) | |
| { | |
| if (tex != null && tex.name.Contains("Unused")) | |
| { | |
| unusedTextures.Remove(tex); | |
| Resources.UnloadAsset(tex); // 卸载未使用的纹理资源 | |
| } | |
| } | |
| } | |
| } |
三、Unity DOTS和ECS的内存管理
Unity DOTS(Data-Oriented Technology Stack)是一套基于数据导向的技术栈,旨在提高游戏的性能和可维护性。在ECS(Entity Component System)中,实体和组件以内存块的形式存在,可以提高内存访问的效率。
- EntityManager
EntityManager类负责创建、销毁实体和组件,并管理它们的内存。以下是一个示例代码:
| using Unity.Entities; | |
| public class MySystem : SystemBase | |
| { | |
| private EntityManager entityManager; | |
| protected override void OnCreate() | |
| { | |
| entityManager = World.DefaultGameObjectInjectionWorld.EntityManager; | |
| } | |
| protected override void OnUpdate() | |
| { | |
| // 创建一个实体 | |
| Entity entity = entityManager.CreateEntity(); | |
| // 向实体添加一个组件 | |
| ComponentType componentType = typeof(MyComponent); | |
| entityManager.AddComponent(entity, componentType); | |
| } | |
| } | |
| public struct MyComponent : IComponentData {} |
- 内存回收
当实体或组件不再使用时,EntityManager类会自动回收它们的内存,避免内存泄漏和内存碎片的问题。
四、性能优化技巧
- 使用结构体定义组件
在ECS中,组件是实体的属性。为了提高性能,建议使用结构体来定义组件,以减少内存占用和内存访问的时间。 - 批处理
批处理可以将多个实体和组件一起处理,从而减少内存访问的时间。
通过以上技术和代码实现,开发者可以有效地控制Unity3D游戏的内存使用,提高游戏性能和稳定性。在实际开发中,应根据游戏的具体需求选择合适的内存管理策略和优化技术。
更多教学视频
Unity3Dwww.bycwedu.com/promotion_channels/2146264125
相关文章:
Unity3D游戏的内存控制详解
前言 Unity3D是一款流行的游戏引擎,支持多种平台,包括PC、移动设备和VR等。随着游戏的复杂性不断提高,Unity3D的内存管理变得尤为重要。本文将详细介绍Unity3D游戏中的内存控制技术,包括自动内存管理、对象池、延迟加载资源和手动…...
《数据结构》--栈【概念应用、图文并茂】
本节讲完栈下次再讲一下队列,最后补充一个串,我们的线性结构基本就完事了。下图中黄色框框圈中的是我们今日份内容(分为两篇博客): 知识体系图 栈(Stack-LIFO)结构 栈的基础概念 栈(Stack)是一个后进先出(Last-In-First-Out)的一个特殊数据…...
国外电商系统开发-运维系统文件下载
文件下载,作者设计的比较先进,如果下载顺利,真的还需要点两次鼠标,所有的远程文件就自动的下载到了您的PC电脑上了。 现在,请您首选选择要在哪些服务器上下载文件: 选择好了服务器以后,现在选择…...
【CSS in Depth 2 精译_045】7.1 CSS 响应式设计中的移动端优先设计原则(上)
当前内容所在位置(可进入专栏查看其他译好的章节内容) 第一章 层叠、优先级与继承(已完结) 1.1 层叠1.2 继承1.3 特殊值1.4 简写属性1.5 CSS 渐进式增强技术1.6 本章小结 第二章 相对单位(已完结) 2.1 相对…...
在线教育新篇章:SpringBoot系统开发策略
2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统,它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等,非常…...
cmdsh
#!/bin/bash #set -x bindirname "$0" bincd "$bin"; pwd echo $bin if [ $# -lt 2 ] then echo “Usage: ./runRemoteCmd.sh Command MachineTag” echo “Usage: ./runRemoteCmd.sh Command MachineTag confFile” exit fi cmd$1 tag$2 if [ a’ 3 ′…...
一键生成PPT的AI工具-Kimi!
一键生成PPT的AI工具-Kimi! 前言介绍Kimi为什么选择Kimi如何使用Kimi在线编辑PPT下载生成的PPT自己编辑 结语 😀大家好!我是向阳🌞,一个想成为优秀全栈开发工程师的有志青年! 📔今天不来讨论前后…...
java.lang.NoClassDefFoundError: kotlin/Result解决方案
问题 在控制窗口上虽然报错是找不到对应的class,但是呢在我们导入kotlin的后,还是报相同的异常,在网上查找了各种资料,都没有解决方案。 问题分析 在idea2021之后,kotlin都使用远程仓库(kotlinx-coeouti…...
LSTM的变体
一、GRU 1、什么是GRU 门控循环单元(GRU)是一种循环神经网络(RNN)的变体,它通过引入门控机制来控制信息的流动,从而有效地解决了传统RNN中的梯度消失问题。GRU由Cho等人在2014年提出,它简化了…...
LeetCode讲解篇之852. 山脉数组的峰顶索引
文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 我们可以采用二分查找,每次查询区间中点元素与中点下一个元素比较 如果中点元素大于其下一个元素,则表示从中点开始向右是递减趋势,那峰值索引一定小于等于中点,我…...
矿井人员数据集,用于目标检测,深度学习,采用txt打标签,即yolo格式,也有原文件可以自己转换。总共3500张图片的数据量,划分给训练集2446张,
矿井人员数据集,用于目标检测,深度学习,采用txt打标签,即yolo格式,也有原文件可以自己转换。总共3500张图片的数据量,划分给训练集2446张: ### 矿井人员数据集用于目标检测的详细说明 #### 1. …...
消息队列RabbitMQ
文章目录 1. 简介与安装2. 基本概念3. SpringAMQP4. 交换机类型5. 消息转换器5.1 默认转换器5.2 配置JSON转换器 6 生产者的可靠性6.1 生产者超时重连机制6.2 生产者确认机制 6. MQ的可靠性6.1 数据持久化6.2 惰性队列 Lazy Queue 7. 消费者的可靠性7.1 消费者确认机制7.2 失败…...
RabbitMQ概述
什么是MQ MQ (message queue)消息队列 MQ从字⾯意思上看,本质是个队列,FIFO先⼊先出,只不过队列中存放的内容是消息(message).消息可以⾮常简单,⽐如只包含⽂本字符串,JSON等,也可以很复杂,⽐如内嵌对象 RabbitMQ是MQ的一种实现,是Rabbit 企业下的⼀个消息队列产…...
Golang学习路线
以下是一条学习Golang(Go语言)的路线: 一、基础入门 1. 环境搭建 安装Go编译器,在官网(https://golang.org/dl/)下载适合操作系统的安装包并配置好环境变量。 2. 语法学习学习变量、数据类型(…...
Flink从ck拉起任务脚本
#!/bin/bashAPP_NAME"orderTest"CHECKPOINT_BASE_PATH"hdfs:///jobs/flink/checkpoints/aaa-test/"is_running$(yarn application -list | grep -w "$APP_NAME" | grep -c "RUNNING")if [ $is_running -gt 0 ]; thenecho "应用程…...
GADBench Revisiting and Benchmarking Supervised Graph Anomaly Detection
Neurips 23 推荐指数: #paper/⭐⭐⭐ 领域:图异常检测 胡言乱语: neurips 的benchmark模块的文章总能给人一些启发性的理解,这篇的insight真有意思。个人感兴趣的地方会加粗。此外,这篇文章和腾讯AIlab合作ÿ…...
某象异形滑块99%准确率方案
注意,本文只提供学习的思路,严禁违反法律以及破坏信息系统等行为,本文只提供思路 如有侵犯,请联系作者下架 该文章模型已经上线ocr识别网站,欢迎测试!!,地址:https://yxlocr.windy-rain.cn/ocr/slider/6 所谓的顶象异形滑块,是指没有采用常规的缺口,使用各种形状的…...
CDN绕过学习
1.什么是CDN? CDN就是分布在各个地区的服务器,这些服务器储存着数据的副本。 哪些服务器比较接近你,当你发起请求时,提前就会快速为你提供服务。 总结来说就是: 其实就是用来加速访问的,以及缓解压力&a…...
SpringBoot日常:redission的接入使用和源码解析
文章目录 一、简介二、集成redissionpom文件redission 配置文件application.yml文件启动类 三、JAVA 操作案例字符串操作哈希操作列表操作集合操作有序集合操作布隆过滤器操作分布式锁操作 四、源码解析 一、简介 Redisson 是一个在 Redis 的基础上实现的 Java 驻内存数据网格…...
npm包管理深度探索:从基础到进阶全面教程!
目录 一、npm概述1、npm简介(1)什么是npm?(2)npm的核心功能(3)npm的工作原理(4)npm的优势(5)npm的局限性(6)总结 2、npm的…...
【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
2025年能源电力系统与流体力学国际会议 (EPSFD 2025)
2025年能源电力系统与流体力学国际会议(EPSFD 2025)将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会,EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...
遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
Objective-C常用命名规范总结
【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...
Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...
