原创文章如需转载请注明:转载自风宇冲Unity3D教程学院
U3D内存优化
读了Hog关于内存管理文章, 自己测试了下。
有以下收获:
(1)Unity的Profiler性能监测是非常准确。
(2)测试复盘的 结果也完全与Hog的一致
(3)但是场景里已经放的物体,删除后,GameObject,Transform等复制出来的是被删掉了.但是引用的贴图却没有被删除。使用Resources.UnloadUnusedAssets并没有效果.
或者实时创建的,依然没有被释放。
最后用了Resources.UnloadAsset(t2d);才得到释放。
(4)Resources.UnloadUnusedAssets(); 释放的资源并不一定是 Resources文件夹下的,内存里有的都算。
(5)有人说删除总是会被延迟到当前帧的末尾:所以需要这样
- IEnumeratorOnLevelWasLoaded(int level)
- {
- Destroy(gameObject);
- yield return null;
- Resources.UnloadUnusedAssets();
- }
但实测发现上并不如此,无论是Destroy(obj); 还是DestroyImmediate(obj); 之后立刻调用Resources.UnloadUnusedAssets();都会被释放。
(6)删除
DestroyImmediate(obj);
t2d = null;
mat=null;
Resources.UnloadUnusedAssets();
t2d是reference到UIAtlas这张贴图,属于direct reference。 而mat这个材质上的mainTexture是reference到UIAtlas,所以mat是indirect reference。 而不管是direct reference 还是indirect reference都必须为null,即t2d及mat都必须为null, 否则UnloadUnusedAssets就不起作用。
所以在Inspector里指定的,有reference,一运行就会自动加载该资源。
(7)Resources.UnloadAsset(t2d);
当使用Resources.UnloadAsset后,若依然有物体用该图,那么物体就变全黑
(8)
可以Destroy引用
- using UnityEngine;
- using System.Collections;
- public class MyTest : MonoBehaviour {
- private GameObject obj;
- void OnGUI()
- {
- if(GUI.Button(new Rect(0,0,100,50),"Create"))
- {
- GameObject tmpPrefab = Resources.Load("myTestPlayer") as GameObject;
- obj = Instantiate(tmpPrefab) as GameObject;
- Instantiate(tmpPrefab);
- }
- if(GUI.Button(new Rect(0,50,100,50),"Delete"))
- {
- Destroy(obj);
- Resources.UnloadUnusedAssets();
- }
- }
- }
也可以自己删自己
- using UnityEngine;
- using System.Collections;
- public class DeleteSelf : MonoBehaviour {
- void Start () {
- Destroy(gameObject,3f);
- }
- }
不光是开始的时候,任何时候加载 物体,里面有引用的话。都会载入都内存里。
结论
资源加载分为静态加载和动态加载,
静态加载: 场景中静态物体加载
动态加载:
(1)public GameObject指向prefab,
(2)Resources.Load,
(3)Assetbundle
其中(1)(2)都是在Instantiate的时候才加载贴图等资源,所以容易在创建物体时有卡顿现象,解决办法是预先Instantiate然后隐藏。(3)是在Assetbundle.Load的时候就加载贴图等资源了,Instantiate时仅仅时clone,所以不会在创建物体时出现卡顿现象。
不建议使用public GameObject指向prefab。小型游戏可以直接使用Resources.Load然后预创建的方式。大型游戏特别是网游建议全部用Assetbundle。但是Assetbundle是不适合快速迭代开发的。个人觉得可行的思路是先快速迭代开发原型,等原型及核心玩法接受实际去玩的验证并通过后,再使用Assetbundle并采用 模块->拼接的方法进行开发。
Application.LoadLevel是会自动释放上一个场景所占用的内存的,包括动态创建的物体(但是不包括AssetBundle文件自身的内存镜像,那个必须要用Unload来释放,用.net的术语,这种数据缓存是非托管的。)。因此短时间的场景或者 场景里内存在初进场景后增加幅度不大的时候,都可以采用场景切换来自动释放内存的。而面对在一个场景里,内存有增加,或者说不断增加各种物体的话。那么就需要Resources.UnloadUnusedAssets。ab的话,则是AssetBundle.Unload
AssetBundle.Unload(flase)是释放AssetBundle文件本身的内存镜像,不包含Load创建的Asset内存对象。
AssetBundle.Unload(true)是释放那个AssetBundle文件内存镜像和并销毁所有用Load创建的Asset内存对象。
AssetBundle.Unload(true)是释放那个AssetBundle文件内存镜像和并销毁所有用Load创建的Asset内存对象。
Reference: