优化脚本性能 Optimizing Script Performance

Posted mimime

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了优化脚本性能 Optimizing Script Performance相关的知识,希望对你有一定的参考价值。

This page gives some general hints for improving script performance on ios.

此页面提供了一些一般的技巧,提高了在iOS上的脚本性能。

Reduce Fixed Delta Time 减少固定的增量时间

Use a fixed delta time value between 0.04 and 0.067 seconds (ie, 15-25 frames per second). You can change this in Edit->Project Settings->Time. This reduces the frequency with which FixedUpdate is called and how often the physics engine has to perform collision detection and rigidbody updates. If you are using a rigidbody for the main character, you can enable interpolation in the Rigidbody Component to smooth out low fixed delta time steps.

使用fixedDeltaTime值在0.04~0.067秒之间(例如,每秒15~25帧之间)。可以在Edit->Project Settings->Time修改这个。这降低了FixedUpdate被调用和物理引擎执行碰撞检测和刚体更新的频率。如果为主角色使用刚体,你可以在刚体组件启用插值来平滑降低固定增量时间步。

Reduce GetComponent Calls 减少GetComponent调用

Using GetComponent or built-in component accessors can have a noticeable overhead. You can avoid this by getting a reference to the component once and assigning it to a variable (sometimes referred to as "caching" the reference). For example, if you are using something like:-

使用GetComponent或内置的组件访问器有明显的性能开销。可以通过获取一次组件的引用并指定给变量来避免这个(有时也被称为"缓存"的引用)。例如,如果你使用像这样:

function Update () {
    transform.Translate(0, 1, 0);
}

...you would get better performance by changing it to:-

......通过改变它会得到更好的性能: -

var myTransform : Transform;

function Awake () {
   myTransform = transform;
}

function Update () {
    myTransform.Translate(0, 1, 0);
}

Avoid Allocating Memory 避免分配内存

You should avoid allocating new objects unless you really need to, since they increase the garbage collection overhead when they are no longer in use. You can often reuse arrays and other objects rather than allocate new ones and doing so will help to minimise garbage collection. Also, you should use structs instead of classes where possible. Struct variables are allocated from the stack like simple types rather than from the heap like object types. Since stack allocation is faster and involves no garbage collection, structs will often improve performance if they are fairly small in size. While large structs will still avoid allocation/collection overhead, they will incur a separate overhead due to "pass-by-value" copying and may actually be less efficient than the equivalent object classes.

你应该避免分配新的对象,除非你真的需要,当他们不再使用时,因为它们增加了垃圾收集的开销。你经常可以重复使用数组和其他物体,而不是分配新的,这样做将有助于减少垃圾收集。此外,在可能的情况下你应该使用结构而取代类。从堆栈(stack)中分配结构变量像简单类型而不是从堆(heap)中,像对象类型。由于堆栈分配速度非常快,不涉及垃圾收集,如果它们的大小相当小,结构往往会提高性能。同时大的结构仍然将避免分配/收集的开销,由于pass-by-value的拷贝将产生一个单独的开销,实际上可能效率低于同等的对象类。

Minimise the GUI 尽量减少GUI

The GUILayout functions are very convenient for automatic spacing of GUI elements. However, this automation naturally comes with a processing overhead. You can avoid some of this overhead by handling the layout manually using the GUI functions. Additionally, you can set a script‘s useGUILayoutvariable to false in order to disable the layout phase completely:-

GUILayout功能对于GUI元素的自动间距都非常方便。然而这种自动化有一些处理性能开销。通过使用GUI功能手动处理布局可以避免这种开销。此外,您可以设置脚本的useGUILayout变量为false,以完全禁用此布局。

function Awake () {
    useGUILayout = false;
}

Use iOS Script Call Optimization 使用iOS脚本调用优化

Most of the functions in the UnityEngine namespace are implemented in C/C++. Calling a C/C++ function from a Mono script involves a performance overhead. You can use iOS Script Call optimization (menu: Edit->Project Settings->Player) to save about 1 to 4 milliseconds per frame. The options for this setting are:-

大多数在UnityEngine命名空间的功能是在C/C++实现。从Mono脚本调用C/C++功能涉及到性能开销。可以使用iOS脚本调用优化(菜单: Edit->Project Settings->Player),节省大约每帧1至4毫秒。

  • Slow and Safe - the default Mono internal call handling with exception support. 
    慢而安全 - 默认的Mono内部调用支持异常处理。
  • Fast and Exceptions Unsupported - a faster implementation of Mono internal call handling. However, this doesn‘t support exceptions and so should be used with caution. An app that doesn‘t explicitly handle exceptions (and doesn‘t need to deal with them gracefully) is an ideal candidate for this option. 
    快而不提供异常 - Mono内部调用处理快速执行。然而,并不提供异常,所以应慎用。应用程序并不需要明确的处理异常,用此选项。

Optimizing Garbage Collection 优化垃圾收集

As mentioned above, it is best to avoid allocations as far as possible. However, given that they can‘t be completely eliminated, there are two main strategies you can use to minimise their intrusion into gameplay:-

如上所述,最好是尽可能避免分配。然而,由于不能完全消除,主要有两种方法可以使用,以减少它们侵入到游戏: -

Small heap with fast and frequent garbage collection
小堆快而频繁的垃圾收集

This strategy is often best for games that have long periods of gameplay where a smooth framerate is the main concern. A game like this will typically allocate small blocks frequently but these blocks will be in use only briefly. The typical heap size when using this strategy on iOS is about 200KB and garbage collection will take about 5ms on an iPhone 3G. If the heap increases to 1MB, the collection will take about 7ms. It can therefore be advantageous sometimes to request a garbage collection at a regular frame interval. This will generally make collections happen more often than strictly necessary but they will be processed quickly and with minimal effect on gameplay:-

这种策略对于长时间的游戏是最好的,有平滑的帧率是主要的考量。像这样的游戏通常会频繁地分配小块,但这些块将只是简单使用。当在iOS上使用这一策略时,典型的堆大小是大约200KB,在iPhone 3G垃圾收集大于需要5ms,如果堆增加到1MB,收集大约需要7ms。因此这是很有利的,有时垃圾收集在一个规则的帧间隔。这通常会使收集发生很多时候绝对必要的,但他们将迅速处理并对游戏影响很小: -

if (Time.frameCount % 30 == 0)
{
   System.GC.Collect();
}

However, you should use this technique with caution and check the profiler statistics to make sure that it is really reducing collection time for your game.

但是,应该谨慎使用这项技术,并检查分析器统计以确保它真的为游戏减少了垃圾收集时间。

Large heap with slow but infrequent garbage collection
大堆慢,但不经常垃圾收集

This strategy works best for games where allocations (and therefore collections) are relatively infrequent and can be handled during pauses in gameplay. It is useful for the heap to be as large as possible without being so large as to get your app killed by the OS due to low system memory. However, the Mono runtime avoids expanding the heap automatically if at all possible. You can expand the heap manually by preallocating some placeholder space during startup (ie, you instantiate a "useless" object that is allocated purely for its effect on the memory manager):-

这一策略最适合于分配是相对偶发并可在游戏暂停期间处理的游戏。对于堆需要尽可能的大而由于系统内存不足没有那么大,操作系统将杀死应用,这是很有用的。然而,如果可能,在Mono运行时避免自动扩大堆。在启动期间通过预留占位空间可以手动扩展堆(例如,实例化一个无用的对象来分配,纯粹为其在内存管理器的效果)。

function Start() {
	var tmp = new System.Object[1024];

	// make allocations in smaller blocks to avoid them to be treated in a special way, which is designed for large blocks
        for (var i : int = 0; i < 1024; i++)
		tmp[i] = new byte[1024];

	// release reference
        tmp = null;
}

A sufficiently large heap should not get completely filled up between those pauses in gameplay that would accommodate a collection. When such a pause occurs, you can request a collection explicitly:-

一个足够大的堆,在游戏容纳一个收集,暂停之前不应该完全被填满。当这样暂停发生时,应该明确要求收集:

System.GC.Collect();

Again, you should take care when using this strategy and pay attention to the profiler statistics rather than just assuming it is having the desired effect.

再次,使用此策略,应该注意分析器统计情况,而不是仅仅假设它是有预期的效果。

页面最后更新: 2011-10-11

分类:Manual| 翻译: U_鹰

以上是关于优化脚本性能 Optimizing Script Performance的主要内容,如果未能解决你的问题,请参考以下文章

Unity性能优化-官方教程Optimizing graphics rendering in Unity games翻译

java性能优化pdf:Optimizing Java Practical Techniques for Improving JVM Application Performance

loadrunner11的移动端性能测试之脚本优化

JavaScript基础概念之----性能优化

JavaScript 性能优化

WWDC2018 之 优化 App Assets Optimizing App Assets