Unity内存泄露排查实战

这次在一个项目中采用了Unity技术作为客户端开发的核心。在开发完成后释放给到客户的某次体验中,突然发现了放置10分钟后会导致程序直接卡死。于是乎进行了长达2周的排查战役。现将排查分享如下。

采用了Unity memory profile工具,两次内存对照,发现有严重的内存泄露情况产生。有关Unity memory profile工具的安装和使用, 大家可以去度娘search,这个几乎一抓一大把

《Unity内存泄露排查实战》

跑了30分钟样子,在RenderTexture和Texture2D两个内存对象中,消耗了3.35GB和0.84GB内存。

明显产生了内存泄露。

《Unity内存泄露排查实战》

3.5M内存泄露。

《Unity内存泄露排查实战》

0.8M内存泄露。 

 到这里就分析不下去了,不知道哪个函数导致内存泄露。 Unity Memory Profile就只能看到总体的状况。

Unity的Memory Profiler一直就是一个被用户诟病的地方,对于内存的使用量,被谁使用等信息,没有很好的反映。

找了一圈也没有什么更好的办法去找到具体是那一段代码出现问题了。 索性我就在认真看一看Memory Profile。

《Unity内存泄露排查实战》

这个3.5M的内存是RenderTexture创建的。 那说明是RenderTexture这里出现问题了。 我就在代码里面去全局search一下代码,看看是哪里出现问题了。

《Unity内存泄露排查实战》 

这是一段Camera扫码用于去截图放大去识别二维码的代码。看着这里有RenderTexture对象的创建,并且还是一张图片,所以就怀疑是这里出现了内存泄露。同时这里还有一个Texture2D,而另外一个0.84G的正好是Texture2D的内存泄露。这里也创建了一个Texture2D对象。

《Unity内存泄露排查实战》

而这个函数是1秒回调用一次。考虑到内存泄露的速度太快了。 基本上断定就是这段代码导致的内存泄露。

把这段代码注释掉,然后在跑一段时间看看。

12:18的内存快照

《Unity内存泄露排查实战》

12:30的内存快照

《Unity内存泄露排查实战》 

过了12分钟,可以看到RenderTexture对象的内存没有涨,Texture2D的内存就涨了20M左右。基本上判定就是这段代码出错了。

代码的位置基本上通过分析定位到了。

那么分析一下为啥这段代码会导致这么内存泄露呢?

《Unity内存泄露排查实战》 

仔细分析了一下这段代码,创建的rt和tex对象也没有被更多的对象引用住呀, 除了在ScannerQR函数中没有去释放栈对象引用。正常来说当这个栈被弹出的时候这个栈变量都会被释放掉。这样Csharp的GC不应该会回收这部分的内存么?

不至于每次都需要手动调用GC来进行人为强制回收垃圾么。

基于上面的分析, 那么我就先把栈对象rt和tex设置 成null,进行一轮测试。

12:50内存快照

《Unity内存泄露排查实战》

12:52内存快照 

《Unity内存泄露排查实战》 

明显内存在极速膨胀。看来简单的设置为null根本没效果。那就说明RenderTexture以及Texture2D在new的过程中,或者后续的使用过程中后,它的内存是需要额外处理才可以释放掉。 但我肯定是不想用GC的,因为GC一定是一个耗时比较重的策略。

度娘一下,果真看到了一种释放方式:

            rt.Release();

            Destroy(rt);

            Destroy(tex);

那么就用这种方式试试看罗。程序员就是需要多多尝试。

 13:00内存快照

《Unity内存泄露排查实战》

经过16分钟的测试,明显发现了内存没有继续爆发式的增长。至此,问题解决。

反思:

原本会认为,C#和Java一样,创建的对象只要保证没有其他对象引用,自然会被GC在某个关键时刻被回收掉。掉以轻心了,某些接口居然还是需要认为按照规则主动进行释放。下回还是要系统看一看Unity的框架代码,否则极容易出现类似这种内存泄露问题。

 

 

 

    原文作者:freeandperson
    原文地址: https://blog.csdn.net/freeandperson/article/details/120470462
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞