unity堆内存检查工具分享
前言继上次查找lua内存泄露后,最近开始查找unity堆内存的泄露,在网上找了很多资料,其实有挺多都是指向UWA或者URP之类的第三方平台,但是不太想使用第三方平台,想使用开源的脚本或者工具,了解原理和思想。于是这里记录下比较好用的开源脚本和工具。
unity自带profiler
unity检查性能最常用的工具当然是自带的Profiler了,打包时勾上自动连接profiler的选项就可以用真机连接profiler来测试了。
用真机来跑了一段时间游戏后,发现mono堆内存的峰值有96m,虽然不能断定有泄露,但是这个数值也挺高了,需要深入检查看看。另外Texture和render Texture的内存占用也挺高的。
用profiler的memory分页下面的Detailed来打一个当前帧的内存快照,发现确实有部分非当前场景的Texture和一些其他场景用作后处理的render Texture没有去掉,这个得检查看看是否有问题,但是没有对比快照对比功能不好对比是否有泄露问题。
于是上网查找可以dump内存快照用来对比的工具,网上大部分都是指向unity的新memory profiler、UWA和UPR等等。但是由于项目使用的是比较旧的2017.4版本,网上教下载的新memory profiler的都是使用新版本的unity,旧版没有找到如何下载。
内存快照工具
去unity官网查看2017.4的api,发现是有新memory profiler对应的api的,证明在2017也是能使用,于是去GitHub上看看是否有其他工具。寻找了一番后果然找到了多版本通用的dump工具。
工具还是挺不错的,有图形化界面,方便操作,具体就不多介绍了,GitHub里面有更详细的文档。
唯一的不足就是对比功能只给出了数据大小,没有给出新增减少。不过可以导出csv,这样可以自己写个脚本来对比数据。
C#代码内存查看工具
有了上面的工具,查找资源类的内存泄露还是挺方便的,但是Managed堆只给出了对象大小、以及C#内存堆数据,没有每个函数的具体占用内存,看起来不太直观。之前查资料的时候知道UWA是有这个功能的,于是上网查查有没有人分享具体的原理。
经过一番搜索,找到了一个通过il注入的方式来统计函数内存分配的分享,雨松大大写。具体原理就是利用cecil遍历项目用到的程序集中所有的方法体,然后过滤构造方法体、虚函数等,最后在剩下的方法体的开始处和结束处注入统计数据的函数。如果用代码表示就入下面这样。
不过雨松大大没有给出注入的统计函数的代码,只是分享了思路,于是用自己渣渣的C#水平写了一份,然后拿去测试工程以及项目中实际调试,遇到了如下的问题:
1、测试工程中报错,没有找到Assembly-CSharp.dll.mdb
原因:由于是20版的unity,用的.net framework是比较新的,不是生成mdb,而是生成pdb
解决方法:更换较新版本的Mono.Cecil,并且注释注入代码的中的MDB调用
2、移植到项目中报错(具体报错忘记了)
原因:项目使用.net framework 3.5,生成的是mdb
解决:于是使用雨松大大博客推荐的Mono.Cecil 0.9.6版本,并且上面注释掉的MDB调用解开
3、项目中报错没有找到方法体(methodDefinition.Body)
原因:因为项目中有使用到开源代码,这些代码中部分方法是通过dll调用的,这样编译后的il里没有方法体
解决:methodDefinition.Body报空的直接过滤掉
4、注入的结束函数内存减去开始函数的值为负数
原因:因为统计内存的是使用Profiler.GetTotalAllocatedMemoryLong()方法,这个方法是返回unity的当前堆内存,用函数运行结束后的当前堆内存减去开始时的堆内存得出函数运行产生的内存。得出负数的是因为刚好碰上unityGC了,所以结束后的堆内存比开始时的小。
解决:判断如果值为负数就过滤不统计这次调用。当然也可以额外做成GC统计。
这里分享一下测试工程,太水勿喷。
总结:
开源的工具可能用起来没有商业工具那样方便,但是能自己学习原理和改造,而且不会泄露数据。 受益匪浅啊,学到了学到了 写得不错,下次继续 小白参考了您的cecilTest,调试时可以注入并输出结果,打包apk就无法注入了,打出来的包解析后dll文件是未注入Hookutils的,请问这个代码不可以注入并打包到apk中吗?我的unity为2019.4.4版本
页:
[1]