问答 下载 AssetBundle 的 Mono 内存问题

侑虎科技 · 2021年04月28日 · 1482 次阅读

1)下载 AssetBundle 的 Mono 内存问题
​2)Unity 2019 运行时获取 Hierarchy 上预制体资源路径
3)多个 Submeshes 模型合并后的显示问题
4)ToLua 中访问 Time.deltaTime 为 0
5)CacheServer 莫名的断开连接


这是第 242 篇 UWA 技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题,建议阅读时间 10 分钟,认真读完必有收获。

UWA 问答社区:answer.uwa4d.com
UWA QQ 群 2:793972859(原群已满员)

Memory

Q:使用协程 +UnityWebRequest 下载 Bundle 时分配的内存释放不掉。

下载步骤如下:
1. 使用协程 +UnityWebRequest 下载 Bundle;
2. 使用 BinaryWriter 将 UnityWebRequest.downloadHandler.data 的数据写入机器;
3. 调用 UnityWebRequest 的 Dispose 函数;
4. 调用 Resources.UnloadUnusedAssets(),UnityWebRequest.ClearCookieCache() 和 System.GC.Collect()。

下载每一个 Bundle 都会执行如上流程,但是 Profiler 调试真机发现,分配的内存无法释放,会把 Mono 内存越撑越大,请问大家遇到过这种情况吗?

A:之前遇到过类似的问题,题主可以参考一下,我们使用的 Unity 版本是 2018.4.31。

不管是之前的 WWW 还是现在的 WebRequest,都是使用的其成员 DownloadHandler 进行下载。当你访问 “.data” 属性时,其实访问的是一个 “GetData()” 函数的包装,这个函数返回的是一段 native-memory data buffer 的拷贝,这也是问题的根结所在。

第一个可以优化的点就是减少 “.data” 的使用,用临时变量缓存下来。
第二个就是替换 DownloadHandler,Unity 提供了多种 DownloadHandler,我们当时是下载图片,所以用的是 DownloadHandlerTexture,看你的问题,可以试试 DownloadHandlerAssetBundle。

参考:https://docs.unity3d.com/ScriptReference/Networking.DownloadHandlerAssetBundle-ctor.html

感谢 Joke@UWA 问答社区提供了回答

Editor

Q:美术希望在编辑器运行的状态下获取场景 GameObject 实例对应预制体的路径,以前 Unity 2017 是可以通过 var pRoot = PrefabUtility.GetPrefabParent(go); return AssetDataBase.GetAssetPath(pRoot),获取运行时预制路径的。

最近升级到 2019 发现接口已经更新,PrefabUtility.GetPrefabInstanceHandle(targetGameObject)、PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(prefab) 等接口都不能在 Unity 运行的时候去获取 Hierarchy 里面的 GameObject 路径。

我问题里面的关键是运行状态,也就是点了播放,然后获取 Hierarchy 上预制的存储路径。PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(prefab) 不点播放是可以获取,播放了只能获取 Project 上预制的存储路径。

A:PrefabUtility.GetNearestPrefabInstanceRoot:获取最近的预制体实例 Root。
PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot:获取预制体路径。

if (PrefabUtility.IsPartOfPrefabInstance(seletedGo))
{
    string prefabAssetPath = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(seletedGo);
} 

GetPrefabAssetPathOfNearestInstanceRoot 可以获取路径,“PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(prefab)” 这个接口传的不是 Prefab 部分,而是实例的。

如果不行,在 Editor 时,在它身上挂脚本或者别的方式建立映射,Runtime 下再拿。

感谢静风霁@UWA问答社区提供了回答

Mesh

Q:请教下,我测试一个 Skinmesh 合并功能,发现当 Mesh 包含多个 Submeshes 时,合并成功后,无法渲染显示出来。

当测试的 Mesh 不包含 Submeshes 时,可以合并显示。难道 CombineMeshes 只能合并不带 Submeshes 的 Mesh?不知道问题出在哪?有什么解决思路吗?

注:不管是使用 “r.sharedMesh.CombineMeshes(combineInstances.ToArray(), false, false); ” 带上所有材质,还是 “r.sharedMesh.CombineMeshes(combineInstances.ToArray(), true, false) ;” 合并一张贴图材质,带多个 Submeshes 的模型只能合并无法渲染显示出来。不带多个 Submeshes 的模型能够正常合并显示。

A:测试发现,需要对每个 CombineInstance 重新指定三角面,才能正常显示带多个 Submeshes 的模型。

如这段代码:

foreach (SkinnedMeshRenderer smr in allSkineMeshList)
   {
       for (int sub = 0; sub < smr.sharedMesh.subMeshCount; sub++)
       {
           CombineInstance ci = new CombineInstance();
           ci.mesh = smr.sharedMesh;
           ci.mesh.triangles = smr.sharedMesh.triangles; //这里重新指定

           ci.subMeshIndex = sub;
           ci.transform = matrix * smr.transform.localToWorldMatrix;
           combineInstances.Add(ci);
       }

   } 

感谢题主牛头人不服@UWA问答社区提供了回答

Lua

Q:在 ToLua 中访问 Unity 的 Time.deltaTime 始终为 nil,赋值给 Lua 变量也是 0。
PS:在 ToLua 访问 Unity API 之前已经进行过静态绑定,其他 API 都可以被 Lua 正常访问。

为什么 ToLua 中访问 Time.deltaTime 为 0?

A:Lua 的绑定必须写在 Lua 虚拟机启动之后:

感谢题主 yxy@UWA 问答社区提供了回答

Editor

Q:客户端打开 Cache Server 面板测试 Connection 会发现连接不上,然后点击一下服务器的控制台,Enter 一下会提示:

然后客户端才能重新连接,怎么感觉像是失去焦点的意思,这是什么原因呢?

A:Windows 在服务器的控制台右击设置属性/默认值 “取消勾选快速编辑模式”。

感谢 aladdin@UWA 问答社区提供了回答

封面图来源:VaSplineSnag
VaSplineSnag 是提供给 UE4 关卡设计师的样条曲线工具。
https://lab.uwa4d.com/lab/5b8627da02004fb65977efaf


今天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,我们早已在 UWA 问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入,也许你的方法恰能解别人的燃眉之急;而他山之 “石”,也能攻你之 “玉”。

官网:www.uwa4d.com
官方技术博客:blog.uwa4d.com
官方问答社区:answer.uwa4d.com
UWA 学堂:edu.uwa4d.com
官方技术 QQ 群:793972859(原群已满员)

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册