Unity3D学习(十一):关于UI销毁后图集仍然无法释放问题的解决办法
前言
最近进行项目性能优化的时候发现的问题。
问题
从大厅进到单局的过程中,会经过选择英雄和加载两个流程,这两个流程对应的UI界面都会有一张几mb左右的贴图作为背景,在进入单局游戏后这两个UI已经销毁了。
之后调用下对应的Resources的相关接口,按理来说图集贴图就应该释放掉了。
Resources.UnloadUnusedAssets()
然而并没有,用Profiler检查了,发现被父级的层级Layer里的GraphicRaycaster引用了(比如下图的英雄界面背景)。

基本上每次进单局都有10mb左右的内存没释放掉

问题排查
暴力重建
项目主程给我的建议把这层Layer直接Destroy掉重建,这样确实能解决问题,但是有可能摧毁的时候上面还有其他UI,导致UI注册信息还在相关的gameObject却没了,访问UI的时候会抛出NullReference的异常,所以这个方法太简单暴力了,不好。
查阅源码
尝试阅读了GraphicRaycaster的源码,发现它内部维护了两个Graphic的列表


这两个列表只有在发起一次新的射线的时候才会清空(进单局后选人和加载的Layer子节点下不会有新的UI接受触摸射线了),于是猜测可能是List一直没清空导致的图集无法释放。
emmmmm,官方还打上了反序列化的标签,这样编辑器的Debug模式下也无法查看这两个List的数据了。
没办法,拷贝了整个代码到一个新类TestGraphicRaycaster,把这两个标签替换为SerializeField,然后把相关Layer上的GraphicRaycaster用这个脚本替换了下,然后运行游戏。
果然跟猜测的一样,是m_RaycastResults这个列表保存的Graphic没有Clear掉,这样Graphic无法被GC回收,进而导致Graphic持有的图集也无法被释放掉。

找到问题了,那就好解决了。
解决方法
直接清理列表
创建一个新类,把GraphicRaycaster的源码拷贝到新类当中,然后添加一个清理的接口
public void ClearRaycastResults()
{
if(m_RaycastResults != null)
{
m_RaycastResults.Clear();
}
}
使用反射清理列表
如果你没有源码或者不想修改源码,那么用反射获取对应的列表清理也是可以的。
using System.Reflection; //放在你的工具类里 public static void ClearRaycastResults(GraphicRaycaster gRaycaster)
{
if(gRaycaster != null)
{
var fieldInfo = gRaycaster.GetType().GetField("m_RaycastResults", BindingFlags.NonPublic | BindingFlags.IgnoreCase | BindingFlags.Instance);
if (fieldInfo != null)
{
List<Graphic> list = fieldInfo.GetValue(gRaycaster) as List<Graphic>;
if(list != null)
{
list.Clear();
}
}
}
}
然后在释放资源前调用下上述方法清理掉GraphicRaycaster的列表就行了
参考资料
相关信息可以参考我在UnityAnswer上发布的这个问题
Unity3D学习(十一):关于UI销毁后图集仍然无法释放问题的解决办法的更多相关文章
- 关于hasNextInt判断后无限循环输出else项的解决办法
话不多说,上来就是干! import java.util.Scanner; public class Test_hasNextInt { /** * @param args */ public sta ...
- WCF服务运行一段时间后客户端无法连接WCF服务的解决办法 (转)
WCF服务运行一段时间后客户端无法连接WCF服务的解决办法 (转) Windows Communication Foundation (WCF)是Microsoft为构建面向服务的应用提供的分布式通信 ...
- windows7开机后,罗技k380无法自动连接解决办法
问题描述: windows7开机后,罗技k380无法自动连接,必须删除设备后重新发现才能正常连接. 解决办法: 是因为笔记本电脑的蓝牙设置问题.按如下设置即可解决. [Bluetooth设置]-[允许 ...
- redhat图形界面启动后出现桌面但是没有登录界面解决办法
redhat图形界面启动后出现桌面但是没有登录界面解决办法 2014年07月11日 10:50:10 阅读数:7931 redhat Linux一直用着好好地,今天打开只有图像界面背景,没有出现登陆界 ...
- 使用uni-app开发小程序,关于小程序更新后与用户本地不会及时更新解决办法
1.原因分析 在小程序更新开发版本之后,用户本地并没有对之前版本的小程序进行删除,那么再进入小程序的时候的版本是不会发生变化的,这是由于发版是异步执行,因此新版本将会覆盖的比较慢,本质是小程序的启动方 ...
- 【原】安装Win7和Ubuntu双系统后,Win7耳机无声音的解决办法
最近安装了Ubuntu的桌面版,作成了双系统,可是发现了一个问题:进入Win7后有时插耳机会没有声音,外放有声音.后来更新驱动也没有解决问题,最后在网上查到了解决办法. 产生原因:进入Ubuntu后, ...
- hadoop启动后jps查不到namenode的解决办法
最近由于项目需要开始接触hadoop,在配置伪分布式启动后,jps查询进程发现少了namenode,而DataNode却存在. 下面是我的core-site.xml和hdfs-site.xml配置: ...
- idea 导入项目后 有的项目目录结构不展开解决办法
如图:可能会出现这中国情况. 解决办法: 1.一般项目导入完成后,但是目录不展开, 2.出现这种情况一般情况下, 关闭idea close idea ,然后重新导入一遍就OK.
- PHP网站从Apache转移到Nginx后产生404错误的原因和解决办法
原案例分析: 1.原来的网站在wamp环境下搭建完成,一切正常,上传到虚拟主机环境为lnmp,结果访问时可以打开主页,然后点其他页面全部报404错误: 2.经分析得出原因:原网站环境为wamp使用了伪 ...
随机推荐
- C#中载入界面的几种做法
1. 采用事件委托的方法 对象:主窗体:FrmMain 加载窗体:FrmLoading 思路: 在主窗体加载前显示窗体FrmLoading,当主窗体加载完毕后(第一次显示的时候),关闭FrmLo ...
- Servlet学习笔记(一):生命周期
一.Servlet 生命周期: Servlet 生命周期可被定义为从创建直到毁灭的整个过程.以下是 Servlet 遵循的过程:初始化——响应请求——终止——回收 Servlet 通过调用 init ...
- 如何获取浏览器URL中查询字符串的参数?
如何获取浏览器URL中查询字符串的参数? 想要知道怎样解决这个问题,首先我们先认识一下Location对象. Location对象包含了当前页面与位置(url)相关的信息 URL示例:http://w ...
- 魔术布局效果-使用本地JSON数据提供数据服务
在线演示 有社区朋友不知道如何修改外部OpenAPI为本地的JSON服务,这里做一个简单演示. 阅读原文:魔术布局效果-使用本地JSON数据提供数据服务
- 用thinkphp操作session
写了一段代码,对session进行一些常用的操作: <?php namespace Home\Controller; use Think\Controller; class Demo1Contr ...
- Matlab矩阵基本操作(定义,运算)
转自:http://blog.csdn.net/perfumekristy/article/details/8119861 一.矩阵的表示在MATLAB中创建矩阵有以下规则: a.矩阵元素必须在”[ ...
- GDB高级使用方法
1.设置环境变量 用户可以在GDB的调试环境中定义自己需要的变量,用来保存一些调试程序中的运行数据.要定义一个GDB的变量很简单,只需使用GDB的set命令. GDB的环境变量和Linux一样,也是以 ...
- TP框架ajax U方法不解析怎么办?
TP框架中ajax U方法不解析 ajax U方法不解析 ajax url不解析 问题: 造成问题原因: Js 存在单独的 js文件中和html分离了.造成不解析! 解决方法: 方法一:将js放到ht ...
- Oracle学习(五):多表查询
1.知识点:能够对比以下的录屏进行阅读 SQL> --等值连接 SQL> --查询员工信息: 员工号 姓名 月薪 部门名称 SQL> select empno,ename,sal,d ...
- iOS中使用iCloud一些须要注意的地方(Xcode7.2)
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 假设认为写的不好请多提意见,假设认为不错请多多支持点赞.谢谢! hopy ;) 在自己的App中怎样使用iCloud有非常多文章能够查阅,这里 ...