代码检查:高开销的方法调用
性能关键上下文
Unity 事件函数 Update、 LateUpdate 和 FixedUpdate 被非常频繁地调用,通常是每帧或者足够频繁以匹配固定帧率。 同样,作为协程调用的方法可以在每帧挂起和恢复。 显然,这些方法会影响游戏性能,因此需要留意并尽量避免在这些方法及其调用的方法中进行高开销操作。
ReSharper 会通过编辑器边栏的行标记突出显示这些被频繁调用的方法及其调用的每个方法。 这些方法被视为 性能关键上下文。 在该上下文中,ReSharper 会添加 性能指示器 ,以突出显示高开销方法和操作。
这些高亮显示 不是传统的检查 ,比如警告或建议——代码并没有"错误",只是执行了已知开销较大的操作,避免这种代码模式有助于提升你的游戏性能。 通常,这些高亮并没有简单的机制性修复,避免这些操作通常需要较大范围的工作,比如重写甚至部分架构重构。 本质上,这些性能指示器的作用仅仅是提示有高开销操作在发生。 是否需要避免这些操作,以及如何避免,完全由你决定。
需要注意的是,这些性能指示器并不能替代性能分析。 即使某个操作被高亮为高开销,也完全有可能代码的性能已经"足够好"。 务必持续测量!
高开销操作
ReSharper 会在性能关键上下文中突出显示多种已知高开销操作:
对
AddComponent方法的调用对
Find方法的调用对
GetComponent方法的调用对
Debug.Log方法的调用基于字符串的方法调用
对
Camera.main属性的使用使用
null进行 Unity 对象比较
如果一个方法包含上述高开销操作之一,则它自身会被标记为高开销,并且会向原始调用方法回溯。 换句话说,ReSharper 会将任何包含高开销操作或者调用包含高开销操作方法的方法高亮为高开销操作。 例如,给定以下内容:
然后所有方法, Update、 DoSomething 和 DoSomethingExpensive 都会以性能关键上下文标记并在编辑器边栏加标记。 调用 GetComponent 会被标记为高开销操作,并向原始调用方法回溯。 因此,调用 DoSomethingExpensive 会被标记为高开销操作,最后调用 DoSomething 也会被标记为高开销操作。
请注意,如果 API 调用被包裹在 if 块内,依然会被标记为高开销操作。 在编辑时无法判断 if 语句的某个分支被调用的可能性。 if 可能只在对象的生命周期内被调用一次,也可能被调用 50%,或者每次都被调用。 这也是为什么这些高亮只是信息提示而不是警告 —— 这段代码并没有错误,主要是提示此 API 调用开销较高。
传播的上下文
ReSharper 会将性能关键上下文传播到诸如 Update 和 FixedUpdate 等根方法所调用的方法。 这些方法也被视为性能关键上下文,会高亮高开销方法,并将上下文传播至其它被调用方法。 如果性能关键上下文中的某方法调用了高开销 API,则该方法会被视为高开销,并向原始方法回溯。 因此, Update 函数如果其调用的嵌套方法使用了高开销 API,也会将被高亮为高开销方法。
如果看到某个方法被标记为"频繁调用",可以在 Alt+Enter 菜单中使用 传入调用操作。 这样可查看是谁在调用该方法,并可沿着调用树向上查找根 Update 或其它频繁调用方法。
请注意,此功能基于调用跟踪,可获得非常智能且令人惊讶的结果。 例如,当方法作为委托或 Action 传递给其它方法并在其中调用时,也会被标记为频繁调用。
禁用性能检查
可在 中单独禁用高开销方法高亮,也可以在 中禁用所有性能检查或性能指示器边栏行标记。 还可在 中编辑这些高亮的颜色。