Unity优化——脚本优化策略2

 大家好,这里是七七,今天继续来介绍几个Unity脚本优化策略

一、更快的GameObject空引用检查

事实证明,对GameObject执行空引用检查会导致一些不必要的开销。与典型的C#对象相比,GameObject和MonoBehaviour是特殊对象,因为它们在内存中有两个表示:一个表示存在于管理C#代码的相同系统管理的内存中,C#代码是用户编写的(代码托管),而另一个表示存在于另一个单独处理的内存空间中(本机代码)。数据可以在这两个内存空间之间移动,但是每次这种移动都会导致额外的CPU开销和可能的额外内存分配。

这种效果通常称为跨越本机-托管的桥接。如果发生这种情况,就可能会为对象的数据生成额外的内存分配,以便垮桥复制,这需要垃圾收集器最终执行一些内存自动清理操作。本文不细讲。目前只要知道,有许多微妙的方式会意外地触发这种额外的开销,对GameObject的简单空引用检查就是其中之一:

if(gameObject != null){
//对gameObject做一些事情
}

另一种方法是System.Object.ReferenceEquals(),它生成功能相当的输出,起运行速度大约是原来的两倍(尽管它确实稍微混淆了代码的用途)。

  if (!System.Object.ReferenceEquals(gameObject, null)){//对gameObject做一些事情}

这既适用于GameObject,也适用于MonoBehaviour,还适用于其他Unity对象,这些对象既有原生的也有托管的表现形式,比如WWW类。然而,一些基本测试显示任何一个空引用检查方法仍只消耗纳秒。因此,除非执行大量的空引用检查,否则最多只能获得很少的好处。然而,这是一个值得在未来记住的警告,因为它会经常出现。

二、避免从GameObject取出字符串属性

通常,从对象中检索字符串属性与检索C#中的任何其他引用类型属性是相同的;这种检索应该不增加内存成本。然而,从GameObject中检索字符串属性是另一种意外跨越本机-托管桥接的微妙方式。

GameObject中受此行为影响的两个属性是tag和name。因此,在游戏过程中使用者两种属性是不明智的,应该只在性能无关紧要的地方使用它们,比如编辑器脚本。然而,Tag系统通常用于对象的运行时标识,这对于某些团队来说是一个重要问题。

例如,下面的代码会在循环的每次迭代中导致额外的内存分配:

for(int i= 0; i < listOfObjects.Count; i++){if (listOfObjects[i].tag == "player"){//对这个对象做一些事}}

根据对象的组件和类类型来标识对象,以及标识不涉及字符串对象的值,这通常是一种更好的实践,但有时会陷入困境。也许刚开始时并不知道,我们继承了别人的代码库,或者把它当作一种变通方法。假设出于某种原因,标记系统出了问题,我们希望避免本地-托管桥接的开销成本。

幸运的是,tag属性最常用于比较,而GameObject提供了CompareTag()方法,这是比较tag属性的另一种方法,它完全避免了本机-托管的桥接。

用CompareTag()方法来代替上面的直接比较方法,通过profiler分析得到结论:处理时间减少了一半,且由于不会导致内存分配,因此也不会导致垃圾回收。

这说明,必须尽可能避免访问name和tag属性。如果需要对标记进行比较,应该使用CompareTag()。但是,name属性没有对应的方法,因此尽可能使用tag属性。

提示:向CompareTag()传递字符串不会导致运行时内存分配,因此应用程序在初始化期间分配这样的硬编码字符串,在运行时只是引用它们。

 三、使用合适的数据结构

C#System.Collections名称空间中提供了许多不同的数据结构,我们不应该反复使用相同的名称空间。软件开发中一个常见的性能问题是简单地为了便利而使用不适当的数据结构来解决问题。最常见的两种数据结构是List<T>和Dictionary<K,V>。

如果想遍历一边对象,最好用列表,因为它实际上是一个动态数组,对象、引用在内存中彼此相邻,因此迭代导致的缓存丢失最小。如果两个对象相互关联,且希望快速获取、插入或删除这些关联,最好使用字典。例如,可以将一个关卡编号与特定的场景文件相关联,或者将一个代表角色不同身体部分的enum与这些身体部分的Collider组件相关联。

然而,数据结构通常需要同时处理两种情况:快速找出哪个对象映射到另一个对象,同时还能遍历组。通常,该系统的开发人员使用字典,然后对其进行迭代。然而,与遍历列表相比,这个过程非常慢,因为它必须检查字典中每个可能的散列,才能对其进行完全遍历。

在这些情况下,最好在列表和字典中存储数据,以便更好支持这种行为。这需要额外的内存开销来维护多个数据结构,插入和删除操作需要每次从数据结构中添加和删除对象,但迭代列表的好处和迭代字典形成鲜明的对比。

四、避免运行时修改Transform的父节点

在Unity的早期版本中,Transform组件的引用通常是在内存中随机排序的。这意味着在多个Transform上的迭代是相当慢的,因为存在缓存丢失的可能性。这样做的好处是,修改GameObject的父节点为另一个对象并不会造成显著的性能下降,因为Transform操作起来很想堆数据结构,插入和删除的速度相对较快。这种行为是我们无法控制的,所以只能接受。

但是,在Unity5.4以后,Transform组件的内存分布发生了很大变化。从那时起,Transform组件的父子关系操作起来更像动态数组,因此Unity尝试将所有共享相同元素的Transform按顺序存储在预先分配的内存缓冲区的内存中,并在Hierarchy窗口中根据父元素下面的深度进行排序。这种数据结构允许在整个组中进行更快的迭代,这对物理和动画等多个子系统特别有利。这种变化的缺点是,如果将一个GameObject的父物体重新指定为一个对象,父对象必须将新的子对象放入预先分配的内存缓冲区中,并根据新的深度对这些Transform排序,另外,如果父对象没有预先分配足够的空间来容纳新的子对象,就必须扩展缓冲区,以便以深度优先的顺序容纳新的子对象及其所有的子对象。对于较深、复杂的GameObject结构,这可能需要一些时间来完成。

通过GameObject.Instantiate()实例化新的GameObject时,它的一个参数是希望将GameObject设置为其父节点的Transform,默认值是null,把Transform放在Hierarchy窗口的根元素下。在Hierarchy窗口根元素下的所有Transform都需要分配一个缓冲区来存储它当前的子元素以及以后可能添加的子元素(子Transform元素不需要这样做)。但是,如果在实例化之后立即将Transform的父元素重新修改为另一个元素,它将丢弃刚才分配的缓冲区!为了避免这种情况,应该将父Transform参数提供给GameObject.Instantiate()调用,它跳过了这个缓冲区分配步骤。

另一种降低这个过程成本的方法是让根Transform在需要之前就预先分配一个更大的缓冲区,这样就不需要在同一帧中扩展缓冲区,给它重新制定另一个GameObject导缓冲区中。这可以通过修改Transform的HierarchyCapacity属性来实现。如果能够估计父元素包含的子Transform的数量,就可以节省大量不必要的内存分配。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/171431.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

可燃气体监测仪助力燃气管网安全监测,效果一览

城市地下管线是指城市范围内供应水、排放水、燃气等各类管线及其附属设施&#xff0c;它们是保障城市正常运转的重要基础设施且影响着城市生命线。其中燃气引发的事故近些年不断增加&#xff0c;由于燃气管线深埋地下环境复杂&#xff0c;所以仅仅依赖人工巡查难以全面有效地防…

17. Python 数据库操作之MySQL和SQLite实例

目录 1. 简介2. 使用PyMySQL2. 使用SQLite 1. 简介 数据库种类繁多&#xff0c;每种数据库的对外接口实现各不相同&#xff0c;为了方便对数据库进行统一的操作&#xff0c;大部分编程语言都提供了标准化的数据库接口&#xff0c;用户不需要了解每种数据的接口实现细节&#x…

【每日一题】1457. 二叉树中的伪回文路径-2023.11.25

题目&#xff1a; 1457. 二叉树中的伪回文路径 给你一棵二叉树&#xff0c;每个节点的值为 1 到 9 。我们称二叉树中的一条路径是 「伪回文」的&#xff0c;当它满足&#xff1a;路径经过的所有节点值的排列中&#xff0c;存在一个回文序列。 请你返回从根到叶子节点的所有路…

代码随想录算法训练营第四十六天 | 139.单词拆分,多重背包,背包问题总结

目录 139.单词拆分 多重背包 背包问题总结 01背包 完全背包 多重背包 139.单词拆分 题目链接&#xff1a;139. 单词拆分 不要求字典中的单词全部使用&#xff0c;但是要求拆分的单词拆分成的每一个子串都是字典中的单词。 &#xff08;1&#xff09;dp[ i ] 表示前 i 个字符组成…

Re55:读论文 Entities as Experts: Sparse Memory Access with Entity Supervision

诸神缄默不语-个人CSDN博文目录 诸神缄默不语的论文阅读笔记和分类 论文名称&#xff1a;Entities as Experts: Sparse Memory Access with Entity Supervision 模型名称&#xff1a;Entities as Experts (EaE) ArXiv网址&#xff1a;https://arxiv.org/abs/2004.07202 本文…

人工智能基础_机器学习050_对比sigmoid函数和softmax函数的区别_两种分类器算法的区别---人工智能工作笔记0090

可以看到最上面是softmax的函数对吧,但是如果当k = 2 那么这个时候softmax的函数就可以退化为sigmoid函数,也就是 逻辑斯蒂回归了对吧 我们来看一下推导过程,可以看到上面是softmax的函数 可以看到k=2 表示,只有两个类别对吧,两个类别的分类不就是sigmoid函数嘛对吧,所以说 …

Python算法——霍夫曼编码树

Python中的霍夫曼编码树 霍夫曼编码是一种用于数据压缩的技术&#xff0c;通过构建霍夫曼编码树&#xff08;Huffman Tree&#xff09;来实现。这篇博客将详细讲解霍夫曼编码树的原理、构建方法和使用方式&#xff0c;并提供相应的Python代码实现。 霍夫曼编码原理 霍夫曼编…

ubuntu 安装 jetbrains-toolbox

ubuntu 安装 jetbrains-toolbox 官网下载 jetbrains-toolbox jetbrains 官网 jetbrains 官网&#xff1a;https://www.jetbrains.com/ jetbrains-toolbox 官网下载页面 在下载页面点击 Download 安装 jetbrains-toolbox 解压 jetbrains-toolbox 安装包 到指定目录 本案例将…

STM32 默认时钟更改 +debug调试

STM32时钟 文章目录 STM32时钟前言一、修改系统时钟二、DEBUG 前言 为什么我们要改STM32的时钟呢&#xff0c;打个比方在做SPI驱动的时候&#xff0c;需要16M的时钟&#xff0c;但是stm32默认是72的分频分不出来&#xff0c;这个时候我们就要改系统时钟了&#xff0c;那么怎么…

[科普] 无刷直流电机驱动控制原理图解

Title: [科普] 无刷直流电机驱动控制原理图解 文章目录 I. 引言II. 直流电机的原理1. 有刷直流电机和无刷直流电机的区别2. 有刷直流电机的运行原理3. 既是电动机又是发电机 III. 无刷直流电机的原理1. 无刷直流电机与永磁同步电机的区别2. 无刷直流电机的换向控制原理3. 无刷直…

python 笔记 根据用户轨迹+基站位置,估计基站轨迹+RSRP

1 问题描述 已知用户实际的轨迹&#xff0c;和基站的位置&#xff0c;能不能得到用户所连接的基站&#xff0c;以及基站的信号强度RSRP&#xff1f; 1.1 几个假设 这里我们做几个假设&#xff1a; 每个用户有80%的概率连接最近的基站&#xff0c;有20%的概率选择其他的基站连…

4/5G互操作 EPSFB讲解

今天我们来讲一下4/5G之间之间互操作&#xff0c;以及5G的EPSFB是基于什么实现的~ 目录 4/5G互操作 重选 切换 基于覆盖的切换 基于业务的切换 两个面试问题 想要加快4G切换5G的速度&#xff0c;调哪个参数怎么调高效&#xff1f; 想要减慢5G切换4G的速度调哪个参数怎…

2018年5月23日 Go生态洞察:更新Go行为准则

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

knime 中没有column expressions,怎么下载

knime 中没有column expressions&#xff0c;怎么下载 1、打开view&#xff0c;然后找到knime hub&#xff0c;column expression 2、往里面拖动&#xff0c;就可以安装了 3、然后会出现重启&#xff0c;搜索就可以出现啦

【SpringCloud】从单体架构到微服务架构

今天来看看架构的演变过程 一、单体架构 从图中可以看到&#xff0c;所有服务耦合在一起&#xff0c;数据库存在单点&#xff0c;一旦其中一个服务出现问题时&#xff0c;整个工程都需要重新发布&#xff0c;从而导致整个业务不能提供响应 这种架构对于小项目而言是没有什么…

OSG编程指南<十二>:OSG二三维文字创建及文字特效

1、字体基础知识 适当的文字信息对于显示场景信息是非常重要的。在 OSG 中&#xff0c;osgText提供了向场景中添加文字的强大功能&#xff0c;由于有第三方插件 FreeType 的支持&#xff0c;它完全支持TrueType 字体。很多人可能对 FreeType 和 TrueType 还不太了解&#xff0c…

【AUTOSAR】【通信栈】ComXf

AUTOSAR专栏——总目录_嵌入式知行合一的博客-CSDN博客文章浏览阅读292次。本文主要汇总该专栏文章,以方便各位读者阅读。https://xianfan.blog.csdn.net/article/details/132072415 目录 一、概述 二、限制说明

深度学习第3天:CNN卷积神经网络

☁️主页 Nowl &#x1f525;专栏《机器学习实战》 《机器学习》 &#x1f4d1;君子坐而论道&#xff0c;少年起而行之 ​ 文章目录 介绍 CNN的主要结构 卷积层 激励层 池化层 Kears搭建CNN 搭建代码 直观感受卷积的作用 结语 介绍 卷积神经网络&#xff08;Convol…

vs2019中出现Debug Error的原因

一般出现这种错误表示你的某个变量没有正确赋值&#xff0c;或者说本身在你的C程序中加了assert断言&#xff0c;assert的作用是先计算表达式expression,如果其值为假&#xff0c;那么它会打印一条错误信息 #include<assert.h> void assert(int expression); 例子&…

皮尔逊相关性分析的matlab实现,简介和实例

皮尔逊相关性分析&#xff08;Pearson correlation analysis&#xff09;是一种常用的统计方法&#xff0c;用于衡量两个变量之间的线性关系强度和方向。它通过计算两个变量之间的协方差和标准差来衡量它们之间的相关性。皮尔逊相关系数的取值范围为 -1 到 1&#xff0c;其中 -…