unity内部:内存 和 性能(以及Unity5的升级优化)


      我们的脚本代码里经常会需要访问gameObject引用或者某个组件的引用,最好的方式当然是在脚本Awake的时候就把这些可能访问的东西都缓存下来;如果需要访问临时gameObject实例的某属性或者临时某组件的gameObject实例,在能够确保组件一定存在(可以使用[RequireComponent( typeof(AudioSource ))] 如果没有自动添加移除不了!)的情况下,可以用属性访问,毕竟属性访问比GetComponent要快上一倍,但是如果不能确定组件是否存在,甚至是需要对组件的存在性做判断时,一定不要用对属性访问结果判空的方式,而要用GetComponent,这里面节省的开销不是一点半点。

而在unity5中你是没得选择了,因为没有了属性访问器。 看看下图的 GameObject类的对比。(4.6和5.0版本)

??

unity内部:内存 和 性能

Topics
??Memory Overview
??Garbage Collection
??Mesh Internals
??Scripting
??Job System

一、?Memory Overview

Memory Domains内存域
??Native (internal)本地 (内部)
??Asset Data: Textures, AudioClips, Meshes
??Game Objects & Components: Transform, etc..
??Engine Internals: Managers, Rendering, Physics, etc..
??Managed - Mono
??Script objects (Managed dlls)
??Wrappers (包装类)for Unity objects: Game objects, assets,components

??Native Dlls
??User’s dlls and external dlls (for example: DirectX)

Native Memory: Internal Allocators本机内存: 内部分配器
??Default
??GameObject
??Gfx 图形和渲染相关
??Profiler事件探查器
               5.x: 在 Dll 中使用本机的分配器公开的 API

Managed Memory托管的内存
??Value types值类型 (bool, int, float, struct, ...)

? 在堆栈内存中存在。当从堆栈中移除时取消分配。没有GC。

??Reference types (classes) 引用类型 (类)

? 在堆上存在,当长时间不再被引用时都由mono/.net GC删除。

??包装为 Unity Objects :

??GameObject

??Assets : Texture2D, AudioClip, Mesh, …

??Components : MeshRenderer, Transform, MonoBehaviour

Mono Memory Internals

??Allocates system heap blocks for internal allocator(为内部分配器分配系统堆块)

??Will allocate new heap blocks when needed( 在需要时将分配新的堆块)

??Heap blocks are kept in Mono for later use( 堆块保持在Mono中以后使用)

??Memory can be given back to the system after a while( 当过一段时间内存可以被交还给系统)

?......但是它取决于平台è? ,别指望它

??Garbage collector cleans up(垃圾回收器清理)

??Fragmentation can cause new heap blocks even though memory is not exhausted(碎片可以导致新的堆块,即使内存不耗尽)

二、Garbage Collection

Unity Object wrapper(封装)

??Some Objects used in scripts have large native backing memory in unity(在unity中在脚本中被使用的一些对象有大批的本机支持内存)

? 直到运行Finalizers终结器内存才会释放

Mono Garbage Collection

?? GC.Collect

??Runs on the main thread when(运行在主线程上当:

??Mono exhausts the heap space( Mono耗尽堆空间)

??Or user calls System.GC.Collect()(或用户调用 System.GC.Collect())

?? Finalizers终结器
     ??Run on a separate thread(运行在一个单独的线程上当:

??Controlled by mono(由mono控制

??Can have several seconds delay(可以有几秒钟的延迟

?? Unity native memory(unity本机内存

??Dispose() cleans up internal memory(Dispose () 清理内部内存

??Eventually called from finalizer( 最终从finalizer终结器调用

??Manually call Dispose() to cleanup(手动调用 Dispose() 清理

Garbage Collection
??Roots are not collected in a GC.Collect(在GC.Collect上Roots不会被收集)

??Thread stacks(线程堆栈)

??CPU Registers(CPU 寄存器)

??GC Handles (used by Unity to hold onto managed objects) GC 句柄 (使用Unity来守住托管对象)

? 静态变量 !!

? Collection的时间尺度与托管的堆的大小

? 您分配的越多,gets变得越慢

GC: Best Practices 最佳做法
??Reuse objects . Use object pools(重用对象,使用对象池)
??更喜欢基于堆栈的分配。使用结构而不是类
? System.GC.Collect 可以用于触发collection
??手动调用 Dispose立即清理

Avoid temp allocations避免临时分配
??Don’t use FindObjects or LINQ
??Use StringBuilder for string concatenation
??Reuse large temporary work buffers(重用大量临时工作缓冲区)
??ToString()
??.tag 改用 CompareTag() 方法

Unity API Temporary Allocations(临时分配)
一些例子:
??GetComponents<T>
??Vector3[] Mesh.vertices
??Camera[] Camera.allCameras
??foreach

?? does not allocate by definition(定义不会分配)

?? However, there can be a small allocation, depending on the implementation of .GetEnumerator()

? 然而,根据具体的.GetEnumerator()实现可能会有 small有小的分配

5.x: 正在研究新的非分配non-allocating版本

Memory fragmentation内存碎片
??Memory fragmentation is hard to account for(内存碎片很难解释)

??Fully unload dynamically allocated content(完全卸载动态分配内容)

? 切换到一个空白场景,在next level之前

??This scene could have a hook where you may pause the game long enough to sample if there is anything significant in memory

??Ensure you clear out variables so GC.Collect will remove as much as possible
? 确保你clear变量,GC.Collect将删除尽可能多地

? 尽可能避免分配
? 重用对象尽可能在scene play下
??Clear them out for map load to clean the memory(把它们清理干净memory的地图加载)

Unloading Unused Assets卸载未使用的资产
??Resources.UnloadUnusedAssets 将触发资产垃圾回收

?他是搜索所有unreferenced assets 和卸载他们

?他是一个async operation异步操作的

? 它loading 一个 level后在内部被调用

? Resources.UnloadAsset 是最好的

? 您需要知道到底您需要Unload卸载什么

?Unity而不必全部扫描

? Unity 5.0: 多线程的asset垃圾回收

三、Mesh Internals

Mesh Read/Write Option
??它允许您在运行时修改mesh

??如果启用enabled, Mesh的系统副本会保留在内存中

??enabled是默认
? 在某些情况下,禁用此选项不会减少内存使用量

??Skinned meshes皮肤网格

??iOS

Unity 5.0: disable by default默认情况下是禁用 – under consideration

Non-Uniform scaled Meshes非均匀缩放网格
我们需要正确转换的顶点法线
??Unity 4.x:

? 在 CPU 上变换transform网格mesh

? 创建数据的额外副本

??Unity 5.0

? 在 GPU 上缩放Scaled

? 不再需要额外的内存

Static Batching

这是什么?
??它是优化,减少了draw calls 和状态改变的数量

他如何使用?
? 在player settings + Tag对象为static。如下:

它内部如何工作?
??Build-time 生成时间: Vertices are transformed to world- space顶点转换为世界空间

??Run-time运行时间: Index buffer is created with indices of visible objects索引缓冲区创建与指数的可见对象

Unity 5.0:
??Re-implemented static batching without copying of index buffers重新实施静态配料而不复制索引缓冲区

Dynamic Batching

这是什么?

? 类似于静态配料,在运行时对象是non-static
他如何使用?
??在player settings

??no need to tag. it auto-magically works…无需标记。它自动神奇地工作......

它内部如何工作?
??objects are transformed to world space on the对象转换到世界空间上
CPU
? 创建临时的 VB & IB
? 在一个draw call 中呈现Rendered

Unity 5.x:  我们正在考虑使每个平台参数

Mesh Skinning
根据平台的不同实现:
??x86: SSE
??iOS/Android/WP8: Neon optimizations
??D3D11/XBoxOne/GLES3.0: GPU
??XBox360, WiiU: GPU (memexport)
??PS3: SPU
??WiiU: GPU w/ stream out
Unity 5.0: Skinned meshes 通过共享实例之间的索引缓冲区使用较少的内存

四、Scripting(重要!)

Unity 5.0: Mono

??No upgrade不能升级
??Mainly bug fixes主要 bug 修复
??New tech in WebGL: IL2CPP新科技在 WebGL: IL2CPP
? http://blogs.unity3d.com/2014/04/29/on-the-future-of-web-publishing-in-unity/
? 敬请: 会有关于它的博客文章

GetComponent<T>       
它要求游戏物体,得到一个指定类型的组件:
??The GO contains a list of Components
? GO包含Components组件的列表

? 每个组件类型被比作 T
? 第一个组件的类型 T (或从 T 派生),将返回给调用方
? 不太多的开销,但它仍然需要调入本机代码

Unity 5.0: Property Accessors属性的访问器
? 大多数accessors将在Unity 5.0中被移除

? 目的是减少依赖,因此提高模块化
? Transform将仍然被保留

? 现有的脚本将被转换。示例:

in 5.0:

Transform Component
? this.transform 是和 GetComponent<Transform>() 一样
?? transform.position/rotation 需要:

??find Transform component

??Traverse hierarchy to calculate absolute position遍历层次结构来计算绝对位置

??Apply translation/rotation

?? transform internally stores the position relative to the parent变换在内部存储的位置是相对于父级

??transform.localPosition = new Vector(…) →  简单的赋值

??transform.position = new Vector(…)→  costs the same if no father, otherwise it will need to traverse the hierarchy up to transform the abs position into local

? transform.position = 新的 Vector(...)→  如果没有父亲代价是一样的,否则它将需要本地遍历hierarchy得到transform的位置绝对值

? 最后,将通过messages通知其他组件 (对撞机、 刚体、 轻型、 相机、)。

Instantiate
API:

??Object Instantiate(Object, Vector3, Quaternion);

??Object Instantiate(Object);

Implementation执行:

??克隆GameObject Hierarchy and Components

??Copy Properties复制属性

??Awake

??Apply new Transform (if provided)适用新的变换 (如果提供)

Instantiate cont..ed
??Awake 可以是昂贵的
? AwakeFromLoad (主线程)

??clear states清理状态

??internal state caching内部状态缓存

??pre-compute预先计算

Unity 5.0:

??Allocations have been reduced分配已被减少

? 一些内部的循环,用于复制的数据进行了优化

JIT Compilation(JIT 编译)
这是什么?
? 在进程中从 CIL 代码生成机器代码,在应用程序运行期间
Pros:优点:
? 为当前平台,它生成优化的代码

Cons:缺点:
?? Each time a method is called for the first time, the application will suffer a certain performance penalty because of the compilation
? 每次方法被第一次调用时,应用程序因为汇编将受到某些性能处罚

JIT compilation spikes
pre-JITting怎么样?

? RuntimeHelpers.PrepareMethod 是行不通的:


....MethodHandle.GetFunctionPointer() 比较好

五、Job System

Unity 5.0: Job System (internal)
job system的目标:

? 基于多线程的代码 可以很容易地写得很高效率的工作

??The jobs should be able to run safely in parallel to script code
? jobs工作应该能够安全地平行的运行脚本代码

Job System: 它是什么 ?

? 它是一个Framework框架,我们打算在现有的和新的子系统中使用的

? 我们想要Animation, NavMesh, Occlusion, Rendering,等等尽可能多的并行运行

? 这最终将导致更好的性能

时间: 2024-10-24 20:44:25

unity内部:内存 和 性能(以及Unity5的升级优化)的相关文章

Unity游戏内存回收的优化(译)

原文Optimizing garbage collection in Unity games.这里是对这篇文章的粗略翻译,当作自己的笔记. Garbage Collector在这里被翻译成名词GC.对于Garbage Collection这里翻译成动词内存回收. 内存垃圾: 代码中销毁了(disposed)但是GC还没有清理的内存. Unity的托管内存的简单介绍 为了理解GC(本文GC指代Garbage Collector)在内存分配和回收时是怎样工作的,我们必须首先了解Unity的引擎代码和

Unity的内存优化方案 (转)

Unity3D占用内存太大的解决方法 最近网友通过网站搜索Unity3D在手机及其他平台下占用内存太大. 这里写下关于Unity3D对于内存的管理与优化. Unity3D 里有两种动态加载机制:一个是Resources.Load,另外一个通过AssetBundle,其实两者区别不大.Resources.Load就是从一个缺省打进程序包里的AssetBundle里加载资源,而一般AssetBundle文件需要你自己创建,运行时 动态加载,可以指定路径和来源的. 其实场景里所有静态的对象也有这么一个

android 内存和性能优化汇总

1.即时编译(Just-in-time Compilation,JIT),又称动态转译(Dynamic Translation),是一种通过在运行时将字节码翻译为机器码,从而改善字节码编译语言性能的技术.即时编译前期的两个运行时理论是字节码编译和动态编译.Android原来Dalvik虚拟机是作为一种解释器实现,新版(Android2.2+)将换成JIT编译器实现.性能测试显示,在多项测试中新版本比旧版本提升了大约6倍. 2. 就像世界上没有免费的午餐,世界上也没有免费的对象.虽然gc为每个线程

冬瓜头答疑:磁盘阵列内部FC-AL的性能问题

冬瓜头答疑:磁盘阵列内部FC-AL的性能问题 作者:冬瓜头出处:IT专家网2009-08-03 09:59 问: 大多数磁盘阵列都是通过两个控制器后端的端口,组成1/2/4条FC-AL环,来连接所有磁盘. FC-AL仲裁环的协议规定,同一时刻只有两个设备能传送数据,也就是说,在一条FC-AL环里面,控制器的一个后端端口充当了发起者的角色,环上的一个硬盘充当了目的地的角色,在一个时刻里,后端端口发出数据读写指令,只有一个硬盘能响应这个指令并传输数据. 那是否就意味着,一条FC-AL环的总体性能,取

javascript动手写日历组件(3)——内存和性能优化(by vczero)

一.列表 javascript动手写日历组件的文章列表,主要是通过原生的JavaScript写的一个简约的日历组件: (1)javascript动手写日历组件(1)——构建日历逻辑:http://www.cnblogs.com/vczero/p/js_ui_1.html (2)javascript动手写日历组件(2)——优化UI和添加交互:http://www.cnblogs.com/vczero/p/js_ui_2.html (3)javascript动手写日历组件(2)——内存和性能优化:h

Windows系统CPU内存网络性能统计第一篇 内存

最近翻出以前做过的Windows系统性能统计程序,这个程序可以统计系统中的CPU使用情况,内存使用情况以及网络流量.现在将其整理一下(共有三篇),希望对大家有所帮助. 目录如下: 1.<Windows系统CPU内存网络性能统计第一篇 内存> 2.<Windows系统CPU内存网络性能统计第二篇 CPU> 3.<Windows系统CPU内存网络性能统计第三篇网络流量> 本篇将介绍统计系统内存使用情况,包括内存使用率.总物理内存大小.可用物理内存大小.总虚拟内存大小,可用虚

Android内存、性能是程序永恒的话题

内存.性能是程序永恒的话题,实际开发中关于卡顿.OOM也经常是打不完的两只老虎,关于卡顿.OOM的定位方法和工具比较多,这篇文章也不打算赘述了,本章主要是来整理一下JVM的内存模型以及Java对象的生与死. 生存空间(内存区域) Java程序运行在JVM之上,如果Java对象是一个有血有肉的生灵,那么它生存环境是怎样的呢?很多人把Java内存分为堆内存(Heap)和栈内存(Stack),实际上这种划分比较出粗糙和片面.比较细致的划分是这样的: 分为程程计数器.虚拟机栈.本地方法栈.方法区和堆.

SQL Server 环形缓冲区(Ring Buffer) -- RING_BUFFER_MEMORY_BROKER 诊断内部内存压力

SQL Server 环形缓冲区(Ring Buffer) -- RING_BUFFER_MEMORY_BROKER 诊断内部内存压力 内存Broker 内存Broker的职责是根据其需求在大内存消费者之间分配内存.内存Broker是一种SQLOS的组件,但是与缓冲池紧密结合.此外,内存Broker只会将缓冲池的内存管理器所控制的内存考虑在内.内存Broker会监视缓冲池的内存需求,以及由大内存消费者所消费的内存.基于所收集的信息,它会估计每个消费者的"最优化"内存分布,并将此信息广播

事件相关的-内存和性能

由于事件处理程序带来的交互能力,在JavaScript中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能. 导致这一问题原因有哪些: 事件相关的处理函数越多,所占用的内存越多,函数是对象,而对象就会占据内存,从而占据内存空间.而内存越多性能就越差. 其次必须事先指定事件处理程序,则需要访问的dom次数增多,会延迟整个页面的交互就绪时间. 事实上从事件处理程序的角度出发,还有那些方法可以提升性能的? 事件委托 由于在一些常用事件是支持冒泡的,所以可以在其父节点或者其祖先节点上获取到对