作为unity开发者,我们使用memory Profiler来查看内存,本期我们项目中Texture2D的内存占有比较高,为了对这块做优化我们先看下内存的占有情况。
step1 使用memory Profiler对手机应用程序截图
打开截取后的内存页面,选择顶部UnityObjects查看下面的数据,展开Texture2D,下面是截取后的数据。
step2对图片数据分析
我们可以看到从直观上看纹理数据可分为两种:
情况1
有正常名字的,这类数据一般是通过本地资源加载进来的,如 Resources.Load(“资源路径”)这种方式加载进来的。
情况2
名字为No Name这种,这种文件有两种可能一种是要被销毁的,另一种是网络下载下来的图片,比如网络下载下来的头像,或者其他要展示的2D图片等等。
step3对于情况1的内存释放
正常情况下我们会采取的操作是销毁物体认为这样会回收内存处理如下
//这样
Destroy(transform.gameObject);
//或者这样
Destroy(gameObject);
但是通过内存分析工具可以看到这样处理后的纹理图片依然驻留在内存中。
出现这样的原因是unity的资源有一层缓存机制,不管是否被调用,在启动资源清理功能前都会驻留在内存中了。
定位到这块问题所以我们修改处理如下
Destroy(gameObject);
//卸载未回收资源
Resources.UnloadUnusedAssets();
//System.GC.Collect();//回收内存
这样通过资源回收处理就可以释放掉这块的内存了(亲测有效),后面的GC调用可以更保险一些,但是因为GC会导致线程卡顿影响用户体验所以不到万不得已不可乱用。
step4对于情况2的内存释放
因为我们是用的图片资源不是从本地resource加载的所以不能通过Resources.UnloadUnusedAssets这个方法卸载掉图片内存所以我们理解只需要销毁物体即可以销毁掉内存的占用即:
//这样
Destroy(transform.gameObject);
//或者这样
Destroy(gameObject);
但是从memory Profiler我们看到图片产生的内存还是未销毁,截图如下
从help里面我们看到虽然调用了物体的销毁处理,但是托管内存依然存在,即该对象的外部引用一直存在导致这个物体一直无法销毁,看到这里我们思路就有了即将托管对象置为空即可。
//下载头像
StartCoroutine(ImageLoadManager.LoadNetImage(IvAvatar,SysConfig.instance.unityAvatar));
//延迟5秒后销毁物体并置空对象
StartCoroutine(LateTest());
IEnumerator LateTest()
{
yield return new WaitForSeconds(5);
Destroy(IvAvatar.gameObject);
IvAvatar = null;
view["Avatar/IvAvatar"] = null;
view.Remove("Avatar/IvAvatar");
Resources.UnloadUnusedAssets();
}
最终通过将物体对象设置为空处理内存被成功回收。