转载自 http://blog.sina.com.cn/s/blog_74c22b210102wz7m.html
标签:texture引用 unloadunusedassets gc.collect
手机卡顿,运行速度慢原因:Memory占用大
手机发热原因:CPU占用大
1. 为什么研究Texture引用计数?让我们先看一张图。
很明显,名为“Backdrop”的贴图引用计数为0,但是它依然占据着1.3MB的内存,如果该内存一直不被回收,就会造成我们常说的内存泄漏。
2. 这引用计数为0是如何出现的?
为了避免其他程序干扰,我建立了一个新场景,来专门研究Texture的引用计数
脚本SpriteTest代码如下:
不点击test1.test2.test3按钮时,UnityProfiler如下
由图可以看出
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如下
由图,此时“Backdrop”引用计数为2,被“1406(Material)”和“SpriteTest(MonoBehaviour)”引用着
注:其实是被SpriteTest中的textext引用着
当点击了test2时,UnityProfiler如下:
由图,此时"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()
这两个函数都是会被自动调用的.