用好静态代码分析,为游戏性能提升助力 -- Unite2017 张黎明分享

发表于2017-05-31
评论0 3.3k浏览

说明: http://forum.china.unity3d.com/data/attachment/forum/201703/24/075619uf8x7sh6car87rc6.jpg.thumb.jpg

关于Unite

Unite大会是由Unity举办的全球开发者大会,至今已有10年的历史。Unite现已成为游戏行业,VR/AR行业中最具有权威性和影响力的活动。

 

 

张黎明:我们就开始了,上一场介绍了一些性能分析的手段都是使用动态的方式去分析性能,就是游戏运行时的时候,使用工具attach上去分析。我下面会介绍一种静态的分析脚本的技术。比较常见的就是性能问题。首先我会介绍一下什么是静态代码分析,然后会介绍它的原理然后怎么样去扩展这个工具。如果程序已经做好以后,再去分析,会花费额外的分析时间。如果人工去检测,也不可避免会有一些遗漏。静态分析会自动化地找到问题。也可以作为一个独立的工具加到你的持续集成的系统里面,完全做到全自动化的分析。

   

这个概念其实也不是一个新的概念,其实你现在用Visual Studio打开看,会发现某些代码下有一条曲线,这是已经使用静态分析给你一些提示,告诉你可能在代码的这个部分会存在有些问题,建议你去检查一下。另外一个还有Visual  Studio里面的插件,就是Resharper。下面会介绍我们今天这个静态分析技术它的原理是什么。首先其实这个工具它是基于Roslyn的编译器,现在微软最新的就是这个编译器。是从VS2015开始开源的。Roslyn提供了非常多的功能,提供了让你通过代码去语义分析,找特定的代码样式。其实我们现在要介绍的这个工具就是我们的Unity的两个开发者开发的,并不是我们官方提供的。这个工具可以和Visual Studio集成,也可以通过命令行来分析你脚本里面存在哪些代码的问题,还可以通过网页的方式来展示。

    

下面看一下它目前提供了哪些代码的选项,这个例子也是这个工具提供的一个例子,下面看一下它目前会检测如何通过反射去获取一个类型,目前C#有三种方式去获取。第一种是typeof,第二种是一个对象的GetType获取对象的类型,还有一种方式是通过GetType传一个字符串获取类型。第三种也是我们不推荐的。这种方式是在网上有一篇文章在专门解释的。因为它有一些GC的内存分配,大家可以去参考一下这篇文章。这里通过静态的脚本分析工具,如果使用了这种方式会给你一个警告,建议你不要使用这个方式。然后是SendMessage会不建议使用,因为对代码的管理不太好。你去寻找这个函数从哪里调过来不是那么方便。OnGUI会产生的内存分配会导致GC的内存卡顿,也不推荐使用。另外,你只要使用了Coroutine的函数,有可能导致GC的内存分配,也建议大家都不要使用。另外像这种update函数,如果是空的,也会告诉你,会有额外的消耗。Tag如果使用等号直接去比较字符串的话,这种方式也会导致有GC内存的分配。然后还有这种Find的函数,也会检测出来,如果在Update都调用了这个,它会提示你建议把它缓存下来。

   

下面简单介绍一下怎么样使用这个插件。首先这个插件它的作者已经把它发布在Visual  Studio里面,你可以去Visual  Studio寻找。就可以打开一个窗口,在这个窗口里面,你可以去查找这个包,搜到以后,你可以看到你自己的工程。你要选择把这个包安装在你的工程里面。类似于一个插件,然后内嵌到你的工程里面才能够生效。安装结束以后就可以生效了。某些代码下面可能比原来多了一些下滑线的曲线。因为Visual  Studio本来就帮你检查出一些问题。像这里,StartCoroutine下划线这里会提示你,建议你不要去使用。其实很多游戏不可避免还是要用的Coroutine。如果没有必要的话尽量通过别的方式去实现。

  

另外在log窗口里面会看到一些警告。你可以比较快速地查找有哪些代码有问题。另外,这是通过命令行的方式执行插件,可以生成一个日志出来。最后一个方式会生成一个网页文件,你可以集成到CI系统里面,每一次更改之后,可以自动地生成一个报告出来。这样的话其他的QA或者Manager就可以马上察看了。

   

最后介绍一下如何扩展这个分析器,因为目前的工具它只是实现了大概十几种代码问题的检测,如果在你的项目里面发现有其他的可以优化的代码的地方,你可能要去扩展它。首先你需要安装Visual  Studio2015或者以上的版本。安装完2015以后需要安装Visual  Studio2015  SDK,这个SDK可以在安装Visual  Studio的时候装,也可以在安装完Visual  Studio之后从菜单里面单独去安装这个SDK。另外可以选择性地更新到最新版,因为Visual  Studio里面还不是它不是最新版的。另外如果你想去debugger这个工具的话,就需要安装这个SDK。下面的例子基于Unity去年关于il2cpp优化的文章,这个文章里面主要讲,如果你使用虚函数,它本身有一些消耗。在某些情况下你是可以避免虚函数的调用和消耗。这个例子我有一个动物类,动物类下面会继承下来一个牛,每个动物都会叫,都会speak,牛的叫声是这样的,猪可能是另外一个叫法。如果你在使用过程中,直接去调用,每一个动物叫的函数,就不可避免有一个虚函数的调用。怎么去解决呢?如果我们明确地知道这个牛不会有另外一个类再去继承这个牛了,我可以把牛声明为sealed,你在这样的声明之后,C# Compiler会帮你去优化,它会把虚函数的调用变成一个普通函数的调用。这个例子会检测有没有一个类是从其他类派生下来的。如果存在这种情况,我就给你一个提示,你可以把它改成一个sealed的类,这样可以避免虚函数的消耗。扩展方法是直接在这个开源的Analyzer工程里面新建一个类,这个类必须继承自这个类,实现三个函数。第一个函数是初始化函数,非常简单,它需要注册一个分析函数,就是下面这个函数。下面这个函数是需要注册到Roslyn内部,它会调用你的这个回调函数。在这个回调函数内部会去判断所有的类,判断这个类是不是继承下来的类,有没有声明为sealed,如果发现一个类满足了这个条件,它会继续检测每个函数是不是一个Override的虚函数。如果这两个条件发现都满足了,它就会输出一个分析的结果出来,分析的结果就是通过第三个函数提供的,这个函数非常简单,就是一些描述性的信息,其实最主要的内容就是最终在警告以及网页里面提示的那个信息,会有一个字符串。这个零会填充成发现类型的名称,说这个方法是一个继承下来的方法,提示你声明为Sealed

   

这一场时间也比较快,最后如果大家发现有更多的分析项加到我们静态脚本分析工具里面,大家可以把你们的经验和知识分享出来,谢谢大家!

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引