Unity内存分析-Texture引用计数

时间:2024-04-07 12:35:18

 

转载自 http://blog.sina.com.cn/s/blog_74c22b210102wz7m.html

标签:texture引用 unloadunusedassets gc.collect

手机卡顿,运行速度慢原因:Memory占用大

手机发热原因:CPU占用大​

1. 为什么研究Texture引用计数?让我们先看一张图。

Unity内存分析-Texture引用计数

​很明显,名为“Backdrop”的贴图引用计数为0,但是它依然占据着1.3MB的内存,如果该内存一直不被回收,就会造成我们常说的内存泄漏。

2. 这引用计数为0是如何出现的?​

为了避免其他程序干扰,我建立了一个新场景,来专门研究Texture的引用计数

脚本SpriteTest代码如下:

Unity内存分析-Texture引用计数

​不点击test1.test2.test3按钮时,UnityProfiler如下

Unity内存分析-Texture引用计数

由图可以看出

1.“Backdrop”现在引用计数为1,被“1406(Material)”引用着。

2. ​1406(Material)又被

a. SpriteTest(MonoBehaviour)

     SpriteTest又被GameObject(GameObject)引用

b. ​UIAtlas(MonoBehaviour)

     UIAtlas又被GameObject(GameObject)​和SpriteTest(MonoBehaviour)引用

3. 图中还框出了正在被引用的Shader、Material

​当点击了test1时,UnityProfiler如下

Unity内存分析-Texture引用计数

​由图,此时“Backdrop”引用计数为2,被“1406(Material)”和“SpriteTest(MonoBehaviour)”引用着

注:其实是被SpriteTest中的textext引用着​

当点击了test2时,UnityProfiler如下:

Unity内存分析-Texture引用计数

​由图,此时"Backdrop”引用计数为0.

如果不点击test3, Backdrop将始终占据着内存1.3M。

注意:如果调用System.GC.Collect()是不会回收这1.3M内存的

非托管资源:必须手动显式释放,这里必须调用Resources.UnloadUnusedAssets();

托管资源:才用​System.GC.Collect()来释放

在.net编程环境中,系统资源分为托管资源和非托管资源。

绝大多数资源都是非托管资源。

托管资源是指资源的引用、销毁是系统自动管理,无需手动操作的资源;而非托管资源是指系统不自动管理,需要手动显示释放的资源,若使用不当,则会造成程序占用内存持续增长。

托管资源的内存管理是靠引用计数进行的,只要保证对象不再被引用,即可在GC的时候将托管资源占用的内存释放。如:将指针变量置null,则该指针之前指向的对象(如果有)​的引用计数减1;指针变量的生命周期结束(临时变量所在的大括号之外、类成员变量所在的对象被释放等)时,指针指向的对象(如果有)的引用计数减1。注意:只要指针的生命周期未结束,会一直保持对对象的引用计数,包括数组、字典等中引用的元素。

非托管资源一般都是先IDispose接口,通过显示调用Dispose()或者Close()方法以释放资源。常见非托管资源有Stream(如FileStream、MemoryStream等)​、StringReader、StringWriter等。一般都是对于流(文件流、内存流、网络流、字符串流等)操作的类。

对于非托管资源,常见的使用方式有:

1.临时变量通过Dispose()或​Close()方法手动释放

MemoryStream s = new MemoryStream(bytes)​;

T data = ProtoBuf.Serializer.Deserialize​(s);

s.Dispose();

2.临时变量使用using关键字

Using(MemoryStream s= new MemoryStream(bytes))​

{ T data = ProtoBuf.Serializer.Deserialize​(s);​ }​

3.成员变量在析构函数中释放

class TestClass{

​FileStream fs;

public TestClass(string path)​ { fs = File.OpenRead(path); }

~TestClas() { fs.Dispose(); }​

}​​

已发现游戏中经常出现的未释放托管资源的问题:

1.解析xml时,创建StringReader对象而为显示释放

XmlReader xmlReader = XmlReader.Create(new StringReader(xmlText));​

2.对于临时创建的MemoryStream的使用

MemoryStream ms = new MemoryStream(bytes)​;

return ms.Deserialize(ms)​ as T;

3 部分FileStream未显示释放​

​最后:

切换场景时,Resources.UnloadUnusedAssets() 

System.GC.Collect()

这两个函数都是会被自动调用的.​