UWA问答 | 博客 | 游戏及VR应用性能优化记录分享 | 侑虎科技 - 厚积薄发
type: channel
link: https://blog.uwa4d.com/category/technology
description: UWA旨在诊断与优化游戏和VR项目开发过程中潜在的运行性能问题，帮助项研发团队快速检测项目运行时的性能瓶颈，高效定位问题根源，及时反馈针对瓶颈问题的深度分析和解决方法。
items: Unity移动端游戏性能优化简谱之 功耗、发热和降频在软件层面的优化
items: Unity移动端游戏性能优化简谱之 以模块思维划分的CPU耗时调优（下）
items: 如何兼顾大量小怪渲染时的合批性能和层次感
items: Unity移动端游戏性能优化简谱之 分门别类地控制运行时内存（下）
items: UE5版本中GC的改动
items: 如何降低Animator的调用次数
items: 引擎Quality设置里的Texture Quality和Global Mipmap Limit有什么区别
items: 在UE5中，预测脚步IK实现-PredictFootIK
items: GPU带宽分析中GPU Non-Base Level Textures过低是什么意思
items: 堆内存对象的Managed Size具体是如何计算的

Unity移动端游戏性能优化简谱之 功耗、发热和降频在软件层面的优化
type: item
date: 2026-03-24T11:11:00+02:00
description: 《Unity移动端游戏性能优化简谱》共分为五个部分，今天向大家介绍文章的最后一部分：功耗、发热和降频在软件层面的优化，包含了移动端高功耗与发热产生机制、功耗与发热的定量数据分析、使用Perfetto的功耗调优实践等多项常见的游戏画面表现讲解。（全文长约3200字，预计阅读时间约15分钟） 前四部分可点击以下对应文章查看： 一、《Unity移动端游戏性能优化简谱之 前言》 二、《Unity移动端游戏性能优化简谱之 分门别类地控制运行时内存（上）》 《Unity移动端游戏性能优化简谱之 分门别类地控制运行时内存（下）》 三、《Unity移动端游戏性能优化简谱之 以模块思维划分的CPU耗时调优（上）》 《Unity移动端游戏性能优化简谱之 以模块思维划分的CPU耗时调优（下）》 四、《Unity移动端游戏性能优化简谱之 达到GPU压力与画面表现间的平衡》 1. 功耗、发热与降频基本原理 1.1 移动端高功耗与发热产生机制 手游运行时功耗由核心计算功耗（CPU/GPU/NPU）、访存功耗、外设功耗（屏幕/射频/传感器/存储）、系统调度开销四部分构成，其中对于手游来说尤其常见和需要关注的情况有： 高负载场景下（战斗、大世界渲染、物理模拟、网络同步），CPU/GPU持续高频运行，功耗可能持续过高； 手机机身散热面积有限，热量无法快速传导至外部，形成热堆积，且往往出现部分硬件模块压力尤其大，发热严重并传导到附近其他模块，使得这些模块也出现性能问题； 功耗与性能并非线性关系，超过能效拐点后，性能小幅提升会带来功耗大幅上涨，发热急剧恶化。 当SoC温度达到温控阈值，Android内核与固件会启动多级热防护机制，强制降低性能以控制发热，多数情况下体现为CPU/GPU频率降低、限制大核调度、减少并发线程数。 降频同时导致了CPU/GPU的算力下降，常直接导致游戏运行过程中帧率暴跌。尤其相对于其他前文讨论的性能问题，该问题反而在一些玩家的高端设备上更加显著，对于一些算力强劲的CPU/GPU，可能计算压力并不足以直接导致掉帧，但发热降频却导致了这些玩家有手机发烫、低帧卡顿等负面体验。 1.2 功耗与发热的定量数据分析 作为开发者和性能优化执行者，观察问题的视角显然还是要与玩家区分。因此，要精准定位功耗与发热的核心诱因，应避免依赖 “手感发烫”、“续航缩短”等主观感受，必须通过定量数据分析建立客观判断标准。正如上文讨论的，移动端游戏的功耗发热本质是硬件模块（CPU/GPU/存储/射频等）持续高负载运行的结果。所以定量分析的核心目标是：明确各硬件模块的功耗占比、定位高功耗场景的时间分布。 不过定量分析功耗发热问题的核心困难是，该问题其实已经脱离了游戏引擎可掌控的范畴，属于非常硬件层的问题。这就导致了不同芯片厂商、不同SoC厂商、不同手机厂商，其散热设计、保护机制等因素的不同都会导致发热和降频的情况互不相同；且他们提供的数据采集接口即便看起来单位一致，其实表示的实际开销也互不相同；在测试过程中，也会受到环境的干扰，比如冬夏气温、插电测试都会导致测试结果受到影响。 所以，应当尽量在固定设备使用可靠的工具进行测试，将数据进行按时间的、优化调试前后的纵向测试，而不是不同硬件、不同工具之间的横向测试。 1.3 使用Perfetto的功耗调优实践 1.3.1 市面上功耗测试工具评测 功耗优化的第一步是精准采集数据，市面上各类功耗测试工具各有优劣，需结合实际测试需求、设备适配性择优选用，以下是主流工具的实操测评与选型建议： （1）GOT Online作为常用性能监测工具，可实时采集帧率、帧耗时、CPU核心频率、内存占用、功耗峰值等核心数据，支持设备截屏、数据导出与对比分析，能直观呈现游戏运行时的功耗波动，基础监测能力在线，但针对细分硬件功耗的拆解能力有限。 （2）Trepn Profiler实测实用性较低，数据采集精度与稳定性难以满足专业调优需求；adb shell dumpsys batterystats指令虽能获取电池消耗数据，但数据维度单一、参考价值不大，仅能作为辅助参考，无法支撑深度功耗分析。 （3）Android Studio自带的Profiler工具，搭载On Device Power Rails Monitor（ODPM）模块，可监测CPU大小核、GPU、内存、屏幕、WiFi等硬件组件的功耗，但缺陷十分突出：不仅需要Debuggable包体，还仅适配Pixel系列机型，且测试时长不宜过长，通用性极差，难以适配主流安卓机型的规模化测试。 （4）Perfetto是移动端功耗测试的最优选择之一，无需Debuggable包体，支持USB/WebSocket连接实时录制。只不过在采集各硬件功耗轨道数据时，谷歌官方只在自己旗下的Pixel品牌手机中进行了专门的插桩，从…

Unity移动端游戏性能优化简谱之 以模块思维划分的CPU耗时调优（下）
type: item
date: 2026-03-24T04:54:00+02:00
description: 《Unity移动端游戏性能优化简谱》从Unity移动端游戏优化的一些基础讨论出发，例举和分析了近几年基于Unity开发的移动端游戏项目中最为常见的部分性能问题，并展示了如何使用UWA的性能检测工具确定和解决这些问题。内容包括了性能优化的基本逻辑、UWA性能检测工具和常见性能问题，希望能提供给Unity开发者更多高效的研发方法和实战经验。 今天向大家介绍文章第三部分：以引擎模块为划分的CPU耗时调优，共10小节，包含了渲染模块、UI模块、物理模块、动画模块、粒子系统、加载模块、逻辑代码、Lua等多个模块等常见的游戏CPU耗时调优讲解。 本章包含6-10小节，1-5小节请点击《Unity移动端游戏性能优化简谱之 以模块思维划分的CPU耗时调优（上）》。 （全文长约14115字，预计阅读时间约30分钟） 文章第一部分《Unity移动端游戏性能优化简谱之 前言》、第二部分《Unity移动端游戏性能优化简谱之 分门别类地控制运行时内存（上）》、《Unity移动端游戏性能优化简谱之 分门别类地控制运行时内存（下）》可戳此回顾，完整内容可前往UWA学堂查看。 6. 粒子系统 围绕粒子系统相关优化更全面的内容可以参考《粒子系统优化——如何优化你的技能特效》。 6.1 Playing粒子系统数量 UWA统计了粒子系统数量和Playing状态的粒子系统数量。前者是指内存中所有的ParticleSystem的总数量，包含正在播放的和处于缓存池中的；后者指的是正在播放的ParticleSystem组件的数量，这个包含了屏幕内和屏幕外的，我们建议在一帧中出现的数量峰值不超过50（1GB机型）。 针对这两个数值，我们一方面关注粒子系统数量峰值是否偏高，可选中某一峰值帧查看到底是哪些粒子系统缓存着、是否都合理、是否有过度缓存的现象；另一方面关注Playing数量峰值是否偏高，可选中某一峰值帧查看到底是哪些粒子系统在播放、是否都合理。 前文提到的控制同种粒子数量上限也是常见方案。 分级策略也是粒子系统优化过程中必不可少的手段。比如对于一个有12345，五种子粒子的火焰特效Prefab，其中345可能是美术同学用来做火焰燃烧时飞溅的火星、飘散的烟尘、空气的波动的，只有12是火焰本体。则低端机上应该考虑只保留12。 虽然我们在讨论粒子系统对耗时的影响时，多数时候还是在讨论粒子系统的渲染开销，无论是CPU端还是GPU端的。但对于粒子系统使用非常重度、数量非常多的项目来说，Playing的粒子过多也会对其本身在CPU端进行更新计算的ParticleSystem.Update()耗时有所影响。 6.2 Culling Mode 为粒子系统设置合理的Culling Mode也是一种有效降低粒子系统CPU端更新耗时的方式。 相关的关键设置为如上图的Simulation Space和Culling Mode。 其中，Simulation Space可选项有Local，World，Custom；CullingMode可选项为Automatic，Pause And Catch-up，Pause，Always Simulate。通常创建的粒子系统的默认选项是Local和Automatic。 我们显然希望当粒子在屏幕外看不到时停止相关运算、减少其耗时开销。因此我们测试在不同设置组合下粒子系统在屏幕外时的ParticleSystem.Update()函数耗时，结果如下： 在Local模式下，只有Culling Mode为Always Simulate有例子更新耗时（没有开启额外的Module）。 在Local模式下，如果粒子系统开启了Collision等Module，那么Culling Mode为Automatic时也会产生耗时。 在Local模式下，如果是Culling Mode为Pause或者Pause and Catch-up，就算有Collision Module也没有耗时。 在World模式下，Culling Mode为Automatic也会有耗时（没有开启额外的Module）。 在World模式下，Culling Mode为Pause，就算有Collision，也没有耗时。 综上，我们可以看到Culling Mode的设置对不同设置的粒子系统开销的限制能力是合理递进的，这说明我们在设置粒子系统时应尽量至少设为Automatic；应慎用Simulation Space为World的粒子；应慎用Collision、Trigger、Noise、Trails这些颇为常见的Module；对于确实要使用Module的粒子，也应考虑进一步调整设置为Pause等以节省耗时。 6.3 Prewarm ParticleSystem.Prewarm作为粒子系统的核心初始化选项，其设计初衷是为了…

如何兼顾大量小怪渲染时的合批性能和层次感
type: item
date: 2026-03-24T03:55:00+02:00
description: 1）如何兼顾大量小怪渲染时的合批性能和层次感 2）Lua堆内存是怎么触发GC的 这是第468篇UWA技术知识分享的推送，精选了UWA社区的热门话题，涵盖了UWA问答、社区帖子等技术知识点，助力大家更全面地掌握和学习。 UWA社区主页：community.uwa4d.com UWA QQ群：793972859 From 问答社区 Q：我们有个类似吸血鬼幸存者的小游戏，画面中有很多怪物，大概有4~5种不同的类型，目前是已经转成了GPU Skinning的方式做渲染，但如果不对怪物做排序，会因为穿插导致无法合批，渲染耗时就很高；而如果做了排序，是能够进行合批，渲染耗时也降下去了，怪物之间却没有了层次感，表现效果也不好，请问该怎么处理？ A：建议做成Texture2DArray版本的材质球，应该纹理顺序就不影响合批了。 欢迎大家转至社区交流： https://answer.uwa4d.com/question/69c0f55a92894f1c4f0c2356 From UWA AI 问答 Q：Lua堆内存是怎么触发GC的？ A：Lua垃圾回收（GC）采用增量式策略，触发机制不依赖真实时间，而是由虚拟机内存分配行为驱动。只有当虚拟机分配新内存时，GC才会推进。 一、触发阈值控制 GC启动由内存使用量倍数决定，通过参数LUA_GCSETPAUSE调节。 默认配置：C API传入值为200。 对应倍率：200%即2倍。 计算逻辑：触发阈值 = 上次GC后内存量*(参数值/100)。 单位校验：若上次GC后内存为100MB，参数值200。 计算过程：100MB*(200/100) = 200MB。 结果：当内存增长至200MB时触发GC。 优化建议：调低该值（如150）可降低内存峰值，但会增加GC频率与CPU开销。 二、回收速度控制 GC推进速度由参数LUA_GCSETSTEPMUL控制。 默认配置：C API传入值为200。 对应倍率：2倍。 作用：表示GC清理速度目标是新增内存速度的两倍，防止内存无限膨胀。 优化建议：数值过低可能导致回收赶不上分配；过高则导致单帧耗时波动增大。 三、监控与优化建议 建议通过性能分析工具观察堆内存曲线。堆内存显著下降意味着发生GC。高频GC降低峰值但增加耗时。若内存持续上涨无下降，需排查泄漏。 优化策略： 减少运行时动态创建Table和闭包，尽量复用对象。 合理预分配内存，避免频繁分配驱动GC。 在加载场景间隙手动调用收集接口，避开帧渲染高峰。 定位高分配热点函数，从代码源头减少内存分配。 调节参数需结合项目内存预算与CPU性能，平衡触发频率与回收速度，实现最佳折衷。 分享链接： https://www.uwa4d.com/main/uwa-shared.html?shareId=dc49a77a-7262-4ca1-98b8-6063b9a13d70 无论是社区里开发者们的互助讨论，还是AI基于知识沉淀的快速反馈，核心都是为了让每一个技术难题都有解、每一次踩坑都有回响。本期分享分别来自UWA AI问答和UWA问答社区，希望这些从真实开发场景中提炼的经验，能直接帮你解决当下的技术卡点，也让你在遇到同类问题时，能更高效地找到破局方向。 封面图来源于网络 今天的分享就到这里。生有涯而知无涯，在漫漫的开发周期中，我们遇到的问题只是冰山一角，UWA社区愿伴你同行，一起探索分享。欢迎更多的开发者加入UWA社区。 UWA官网：www.uwa4d.com UWA社区：community.uwa4d.com UWA学堂：edu.uwa4d.com 官方技术QQ群：793972859

Unity移动端游戏性能优化简谱之 分门别类地控制运行时内存（下）
type: item
date: 2026-03-20T12:10:00+02:00
description: 《Unity移动端游戏性能优化简谱》从Unity移动端游戏优化的一些基础讨论出发，例举和分析了近几年基于Unity开发的移动端游戏项目中最为常见的部分性能问题，并展示了如何使用UWA的性能检测工具确定和解决这些问题。内容包括了性能优化的基本逻辑、UWA性能检测工具和常见性能问题，希望能提供给Unity开发者更多高效的研发方法和实战经验。 今天向大家介绍文章第二部分：资源内存、Mono堆内存等常见游戏内存控制，共13小节，包含了纹理资源、网格资源、动画资源、音频资源、材质资源等多个资源内存以及Mono堆内存等常见的游戏内存控制讲解。 本章包含8-13小节，1-7小节请点击《Unity移动端游戏性能优化简谱之 分门别类地控制运行时内存（上）》。 （全文长约11400字，预计阅读时间约20分钟） 文章第一部分《Unity移动端游戏性能优化简谱之 前言》可戳此回顾，完整内容可前往UWA学堂查看。 8. Render Texture 8.1 渲染分辨率 资源列表中的一些RT资源能反映项目当前的渲染分辨率。对于GPU和渲染模块压力较大的项目，在中低端机型上降低其渲染分辨率是非常直观有效的分级策略。但相关调整比起说影响内存，还是更多地影响GPU片元计算压力和带宽，后文GPU章节会进行更加详细的讨论。 如果一些其他的RT资源分辨率过高也应引起注意，尤其是2048*2048以上的资源。应当排查是否有必要用到如此精细的RT，在低端机上考虑采用更低分辨率的效果。 8.2 抗锯齿 资源列表中展示了RT资源的AA倍数。开启多倍AA会使RT占用内存成倍上升，并对GPU造成压力。建议排查是否有必要开启AA，尤其在中低端机上，可以考虑关闭此效果。 特别的是，在华为部分机型上2倍的AA会失效。即已经造成了性能消耗但没有实际起到抗锯齿效果。 8.3 后处理 一些常见的后处理相关的RT（如Bloom、Blur）是从1/2渲染分辨率开始采样，可以考虑改从1/4开始采样、并减少下采样次数，从而节省内存并降低后处理对渲染的压力。 站在性能优化的角度，在中低端机型上甚至最好分级地关闭各类后处理。围绕一些常见后处理效果的讨论会在下文GPU部分中进一步展开。 8.4 URP下的RT 使用URP时，内存中会多出_CameraColorTexture和_CameraDepthAttachment两份RT资源作为渲染目标，而开启URP相机的CopyDepth和CopyColor设置时会额外产生_CameraDepthTexture和_CameraOpaqueTexture作为中间RT。当资源列表中出现这两种RT时，需要排查确实是否用到CopyDepth和CopyColor，否则应予以关闭以避免不必要的浪费。 9. Shader资源 9.1 ShaderLab Unity 2019.4.20是Shader内存统计方法的一个转折点。在此之前，Shader的内存主要统计在ShaderLab中，而之后则主要统计在Shader资源自身身上。 对于Unity 2019.4.20之前的版本的项目，查看ShaderLab的内存使用Memory Profiler截帧查看。而无论是Shader资源本体还是ShaderLab内存占用过高，都要着手于控制Shader的数量、变体数量和Shader复杂度。 9.2 变体数和复杂度 对于单个Shader资源而言，其内存占用高本质在于其编译后的行数高。因此也可以视为，怎么控制变体的数量和每个变体的平均行数（也就是Shader的复杂度），这两个乘数的问题。 其中，变体数过多是造成一个Shader资源内存占用过大、占用包体过大的主要原因，也是相对比较好和排查和修改的部分。在项目迭代中可能会出现已经被弃用或者没有被实际使用到的关键字，导致变体成倍上升；又或者Shader写的比较复杂，其中一些关键字组合永远不会被用到，从而导致很多变体是多余的。UWA的本地资源检测中提供了Shader检测功能，可以看到变体数量，定位变体数过多的Shader资源。 针对上述情况，Unity提供了回调函数，在项目打AssetBundle包或者Build时线剔除用不到的关键字或关键字组合相关的变体。剔除Shader变体的方法可以参考《Stripping scriptable shader variants》。 而Shader的复杂度同时还涉及到GPU性能相关的优化。具体在后文GPU部分有更加详细的讨论。 9.3 冗余 Shader冗余尤其需要予以关注，Shader的冗余不光导致内存上升，还可能造成重复解析，即运行时不必要的Shader.Parse和Shader.CreateGPUProgram API调用耗时。 一般的做法是，首先使用ShaderVariantCollection这一Unity…

UE5版本中GC的改动
type: item
date: 2026-03-18T04:04:00+02:00
description: 【USparkle专栏】如果你深怀绝技，爱“搞点研究”，乐于分享也博采众长，我们期待你的加入，让智慧的火花碰撞交织，让知识的传递生生不息！ 总览 UE5的GC，相对UE4做了一些改动，但本质没变，依然是基于UObject的标记清扫算法，许多改动都属于优化。 先看GC的各个阶段： 遍历所有Object，标记为不可达 改动较少，增加了RefCount引用方式；更改了Unreachable Flag；增加了单独的RootArray作为根集。 遍历引用关系做可达性分析 改动较多，Batch模式的引用收集；UObject对ClassPrivate和Outer的引用从Token中移除；增加了引用收集的Debug模式。 清理不可达Object 差别不大，依然是分帧Purge，对每个UObject依次执行BeginDestroy, Destroy, FinishDestroy。 除此之外，还有实验性的Increment可达性分析模式，想完全避免可达性分析造成的一帧卡顿，算是一个最大的不同。 对于GC Cluster，变化不大。 另外还有一些其他Tips，比如IsPendingKill接口改成了IsGarbage；ObjectFlags增加了Reachable0，Reachable1，Reachable2等等。 文章中所使用的为UE5.7。 前篇：《UE4垃圾回收》 一、加入引用计数机制 1. RefCounted Flag & RefCount 观察InternalObjectFlags，发现多了一个叫RefCounted的Flag，说明UE的GC在标记清扫的基础上，又加入了引用计数机制，算是一个不小的改动。 引用计数是另一种GC方式，Python中就使用了，简单概括为每个Object记录自己被多少个其他Object引用了，当发现引用计数为0时，就判定自己为垃圾。至于垃圾的清理，可以选择为0时立即清理，也可以选择之后一起清理，反正垃圾是不会再被重新引用到的。 enum class EInternalObjectFlags : int32 { None = 0, //... RefCounted UE_DEPRECATED(5.7, "Use GetRefCount() to determine if a refcount exists instead.") = 1 << 29, ///< Object currently has ref-counts associated with it. //... }; 但有了Flag还不够，得给每个Object再定义一个RefCount属性，记录被引用的次数。UE5.7之前，在FUObjectItem中有一个专门的int32 RefCount属性，但UE5.7开始把RefCount和Flags一起打包成了int64。Flag存在高32位里，RefCount存在低32位里。 这样有个好处，RefCount通常用不了int32这么大，因此可以把更多位数给EInternalObjectFlags用，比如添加一些我们自定义的Flag，或者UE引擎自己扩展。 2. 操作接口 添加RefCount： void UObjectBase::AddRef() const { FUObjectItem* ObjectItem = GUObjectArray.ObjectToObjectItem(this); ObjectItem->AddRef(); } 减去RefCount： void UObjectBase::ReleaseRef() const { FUObjectItem* ObjectItem = GUObjectArray.ObjectToObjectItem(this); ObjectItem->ReleaseRef(); } 获取RefCount： 在引擎内部代码，比如GC过程中，才有获取RefCount的需求，因此UObject上没有获取RefCount的接口，只有FUObjectItem上有。 FORCEINLINE int32 GetRefCount() const { return RefCount; } 哪些地方会给UObject加上引用计数？ 引用计数管理UObject显然更容易出错，万一AddRef/ReleaseRef不成对，就会造成UObject泄漏，引擎中目前也只有StrongObjectPtr使用了。而且是用了RAII模式，在构造和析构中操作RefCount，防止泄漏。StrongObjectPtr可以对一个UObject添加强引用，防止被GC，和AddToRoot类似。下面是StrongObjectPtr中操作的代码： FORCEINLINE_DEBUGGABLE void Rese…

如何降低Animator的调用次数
type: item
date: 2026-03-17T04:43:00+02:00
description: 1）如何降低Animator的调用次数 2）为什么UI相关堆内存对象和纹理资源都占用了较大内存没有释放 这是第467篇UWA技术知识分享的推送，精选了UWA社区的热门话题，涵盖了UWA问答、社区帖子等技术知识点，助力大家更全面地掌握和学习。 UWA社区主页：community.uwa4d.com UWA QQ群：793972859 From 问答社区 Q：现在动画的Culling Mode是Cull Update Transforms，不过从Scene窗口来看，在屏幕外的动画还是在动，这个还需要做其他的什么设置吗，还是我理解的不对？ 然后，之前Camera没有勾选Occlusion Culling，这个有关系吗？ 为什么报告里Animator的调用次数那么多呢？ A：首先，Scene里面确实会影响的，要准确的话，需要关闭Scene窗口。 然后，Camera没有勾选Occlusion Culling，这个没关系的。 最后，在Profiler里面选择那个Animator.ApplyOnAnimatorMove函数，然后打开Related Data，是可以看到具体是哪些对象的： 欢迎大家转至社区交流： https://answer.uwa4d.com/question/69b7a2f392894f1c4f0c2354 From UWA AI 问答 Q1：项目中发现一些UI图片被大量UI对象引用，但这些对象应该已经在代码中调用销毁了，但看起来RUUA和GC都没起到作用，这最终导致我项目中很多UI相关堆内存对象和纹理资源都占用了较大内存没有释放。可能是什么原因？ A：此问题通常由隐性引用、资源标志位或原生资源未释放导致。 排查代码引用链：Lua或C# 中的静态变量、事件监听、闭包可能持有UI对象引用，导致GC无法回收。查看GOT Online报告的Mono引用对象统，若“Destroyed对象数量”持续上涨，说明存在Lua端未解引用，需及时释放引用链。 检查资源标志位：若纹理或对象被标记为 HideFlags.DontUnloadUnusedAsset，Resources.UnloadUnusedAssets将无法卸载它们。需检查代码是否误设该标志，必要时使用DestroyImmediate手动清除。 确认AssetBundle与图集依赖：若引用图集的AssetBundle未完全卸载，图集会驻留。确保AssetBundle.Unload(true)调用正确，或尝试Resources.UnloadAsset。 排查原生资源：RenderTexture不会自动垃圾回收，使用后必须调用Release释放硬件资源，否则会造成显存与内存泄漏。 考虑内存碎片：堆内存高未必是对象未卸载，可能是碎片过多。排查byte[]、MemoryStream等频繁分配对象，使用对象池优化。 建议结合内存快照分析具体占用对象，定位引用源，必要时手动管理资源生命周期，避免过度依赖自动卸载机制。 Q2：我看了UWA报告中的Mono引用对象统计页面，Destroyed对象数确实较高且有上涨，这个具体是什么含义？ A：Destroyed对象数较高且持续上涨是Mono堆内存泄漏的重要预警信号，具体含义如下： 定义说明 Destroyed对象指在C# 端已调用Destroy销毁，但Lua端仍持有引用的Mono层对象。这些对象虽在场景中已被移除，但因Lua端未解引用，仍占用堆内存无法被GC回收。 产生原因 Lua访问Unity对象时，会通过Wrapper代码将对象引用存入容器，以确保C# 端GC不会提前回收。若Lua端未及时释放这些引用，C# 端的Destroy操作无法彻底清理内存，导致对象驻留。 持续上涨的风险 若Destroyed对象数量持续上涨，说明Lua端引用链未正确清理，Mono堆内存会不断累积，最终导致： 内存占用持续增长 GC频率升高，引发卡顿 极端情况下导致内存溢出闪退 排查建议 查看GOT Online报告中Mono对象引用柱状图，确认Destroyed对象趋势 对比不同采样帧，定位对象数量激增的时间点 结合Lua堆内存分配堆栈，查找高分配函数 检查Lua代码中的事件监听、闭包、静态变量是否持有UI对象引用 解决方法 在Lua端及时释放不再使用的对象引用 移除不必要的静态引用和事件监听 使用弱引用管理长期持有的对象 定期调用GC强制回收 若Destroyed对象数稳定在某一水平后不再上涨，通常风险可控；若持续上涨，需优先排查Lua引用链，避免内存泄漏恶化。 分享链接： https://www.uwa4d.com/main/uwa-shared.html?shareId=1d682f3a-b8eb-49d9-a00b-07f0813dddc0 无论是社区里开发者们…

引擎Quality设置里的Texture Quality和Global Mipmap Limit有什么区别
type: item
date: 2026-03-10T04:16:00+02:00
description: 1）引擎Quality设置里的Texture Quality和Global Mipmap Limit有什么区别 2）小游戏上在动画状态机中替换动作会产生较大消耗怎么办 这是第466篇UWA技术知识分享的推送，精选了UWA社区的热门话题，涵盖了UWA问答、社区帖子等技术知识点，助力大家更全面地掌握和学习。 UWA社区主页：community.uwa4d.com UWA QQ群：793972859 From 问答社区 Q：引擎Quality设置里的Texture Quality好像被删掉了？这个新的叫Global Mipmap Limit的设置项看上去是替代？有什么区别吗？ A：Global Mipmap Limit确实替换了Texture Quality，或者说是该功能的升级版，除了仍然是按照设置从Mipmap第0层开始移除外，额外增加了使纹理按照所在Mipmap Limit Group剔除Mipmap层级的设置；并且需要针对具体纹理开启Use Mipmap Limits并设置Group。使用上远比之前Texture Quality的一刀切做法更实用，但相比Texture Streaming的灵活自动处理还是需要投入一定人工成本针对分级进行设置。 欢迎大家转至社区交流： https://answer.uwa4d.com/question/69ae6e7eabed2e338a7dac66 From 问答社区 Q：我们在小游戏项目中使用Animator Override Controller替换动作会产生较大的开销，有什么优化方案吗？ A：替换动画时会对所有的动画重新计算绑定，因此在动画数量本身就很多的情况下，开销也会相应偏高；建议尽可能降低动画的数量，从源头减少合并运算的数据量，并适当削减动画精度，优化动画曲线数据。 这个是大体思路，不过还是比较笼统的，也看看大家有没有什么更好的建议可以取取经。 欢迎大家转至社区交流： https://answer.uwa4d.com/question/69ae3139abed2e338a7dac65 无论是社区里开发者们的互助讨论，还是AI基于知识沉淀的快速反馈，核心都是为了让每一个技术难题都有解、每一次踩坑都有回响。本期分享分别来自UWA AI问答和UWA问答社区，希望这些从真实开发场景中提炼的经验，能直接帮你解决当下的技术卡点，也让你在遇到同类问题时，能更高效地找到破局方向。 封面图来源于网络 今天的分享就到这里。生有涯而知无涯，在漫漫的开发周期中，我们遇到的问题只是冰山一角，UWA社区愿伴你同行，一起探索分享。欢迎更多的开发者加入UWA社区。 UWA官网：www.uwa4d.com UWA社区：community.uwa4d.com UWA学堂：edu.uwa4d.com 官方技术QQ群：793972859

在UE5中，预测脚步IK实现-PredictFootIK
type: item
date: 2026-03-04T04:39:00+02:00
description: 【USparkle专栏】如果你深怀绝技，爱“搞点研究”，乐于分享也博采众长，我们期待你的加入，让智慧的火花碰撞交织，让知识的传递生生不息！ 一、前言与简述 1. 前言 “最终效果可见文尾”。 此篇文章主要是记录开发过程中的一些细节与踩坑，基础动画框架是复刻的ALS，技术方案来自刺客信条基于预测的FootIK。 自己实现过程中也参考了其他大佬的文章（链接放末尾），实现的方法可能存在很多问题，写法也不是很优雅。文章中一些步骤为制作过程记录，也有补录，可能存在顺序或制作内容和正常顺序有差别，有一些细节或者坑可能忘记了，还请见谅。 2. 简述 基于预测的FootIK通过预测角色的落点来计算即将行走的路径，从而通过IK更改脚步和盆骨来适配地形，相较于传统IK会更加灵活（当然也更复杂）。 总体步骤为： 准备脚步数据 预测脚步落点 计算Pelvis数据 计算脚步路径 计算脚步数据 应用数据 二、准备数据与预测 1. 数据准备 在此阶段我们需要在动作中添加一个曲线，通过这个曲线上的时间来告诉我们脚步还有多久会落下，但正如育碧所言：“Absolutely must be automated”，所以我使用的是UE的AnimationModifier来自动的生成曲线，在其中通过对动画信息进行采样，获取当前帧信息。 之后通过获取到的Foot高度（可以更加细致，比如加上脚尖，甚至旋转等）来判断是否为关键点，如果是就记录下来。这里我还开放了FootName和Height的阈值作为参数。 这里获取脚步位置没有直接的函数，需要GetAnimPosAtTime之后去GetBonePose获取，然后根据获取到的脚步落下与脚步抬起关键点来连成曲线。 这里找到落点其实很简单，但生成曲线还比较麻烦，要注意开始点和结束点的连贯，以及曲线应该改成线性。最后就可以得到自动生成的曲线。 2. 脚步预测 在开始之前我创了一个结构体，往里加入很多参数避免之后修改一次就要改函数输入，又要加一堆参数。 在PreDictFootLocation中，思路是通过我们之前生成的脚步落地曲线以及角色的移动速度来获取落点（除去黑框的内容）。 而其中黑框主要是来解决脚步相对位置的问题。 如果你只是一个动作，可以直接写死相对位置，但如果要应用到游戏中的各个动作，它的脚步相对位置会有差距，这个时候我最先想的是：那我实时计算脚步的位置不就好了？ 但脚步会有在后面和在前面，比如落脚的时候不会跟随角色移动，如果用实时位置，那么预测的位置必定很不准确。所以我采取的做法是在落地时记录相对位置，然后用黑框中进行计算。 而这其中的脚步落下是通过一个参数记录上一帧脚步是否落下，如果上一帧落下则更新，同理也可以得到脚步抬起时刻来获取信息。 例如在脚落下时记录脚相对位置，脚步开始位置设为当前脚步位置，上一次的结束位置等。这就是脚步开始位置，而结束位置是通过我们的BoxTrace实时得到的。 这里其实还有个小问题，就是预测的落点会有误差。在移动的时候会逐渐非常缓慢向角色靠近（可看下方视频慢放时）。这个虽然影响不大，但在脚步离台子非常近的时候会有抖动，目前这个问题找了动作、曲线、角色都没找到原因。就先不管了，最后画一画DebugShape就可以得到如下效果： 三、计算Pelvis数据 1. Pelvis起始点与终点 来到Pelvis的计算，首先要获取两脚间的起始点位置（绿线）作为Pelvis计算的起始点和终止点： 这个开始点和结束点的切换是在脚步交错时进行，所以我就直接根据脚步的Y值谁更靠前来决定，当和上一帧不同时则为切换，这个时候更新双脚位置。 注意结束点要在脚落地时一直更新，因为我们之前提到了会有误差，那个落点会一点点向角色靠近，如果只取那一帧的会对不上，所以在脚落地时Pelvis的落点也要一直更新。 这里有些动作会在短时间内交叉两次（比如ALS的冲刺）导致错误，所以还需要对切换加上一个很小的冷却时间，这个时候我们就可以得到下面视频的绿色曲线： 可以看到，我们在上下坡时Pelvis会随着碰撞体一直运动，但我们的预期是在上坡落脚时上升，和在下坡时边下坡边下降，所以首先要固定住Pelvis，之后再去加位移。 2. 上下坡 这里固定Pelvis我之前尝试过使用PelvisOffset‌去做，但是不知道是不是因为更新时机或顺序的问题，会延迟一帧，导致强烈抖动。 所以我最后采取的做法是直接Set角色保持Mesh的高度一直在StartPos处（黑框后面会说）。 此时就可以得到如下效果，可以看到我们角色是一直和开始点保持同样高度： 之后就是处理我们的上坡和下坡的逻辑（平地可视为上坡下坡）来计算Pelvis Addtive Offset Target。 上坡是要落地后采样，并且在结束后Mesh会抬升到新的开始点，所以Addtive要变为…

GPU带宽分析中GPU Non-Base Level Textures过低是什么意思
type: item
date: 2026-03-03T04:13:00+02:00
description: 1）GPU带宽分析中GPU Non-Base Level Textures过低是什么意思 2）为什么不建议用LoadFromMemory接口 这是第465篇UWA技术知识分享的推送，精选了UWA社区的热门话题，涵盖了UWA问答、社区帖子等技术知识点，助力大家更全面地掌握和学习。 UWA社区主页：community.uwa4d.com UWA QQ群：793972859 From UWA AI 问答 Q：GPU带宽分析中GPU Non-Base Level Textures过低是什么意思？ A：GPU Non-Base Level Textures指标过低解析： 在GPU带宽分析中，GPU Non-Base Level Textures指标统计的是GPU采样非Mipmap第0层（即经过缩小处理的层级）纹理的次数。该指标“过低”通常意味着绝大多数纹理采样都强制使用了最高分辨率的第0层（Base Level）。 这并非性能优异的标志，反而往往暗示了潜在的带宽浪费和缓存命中率低的风险，具体分析与优化策略如下： 1. 核心含义与风险 Mipmap未生效或使用不当：正常情况下，随着物体远离摄像机，GPU应自动采样更低分辨率的Mipmap层级。若该指标过低，说明场景中的纹理即便在远处也被强制以最高精度采样。 带宽压力剧增：采样第0层意味着每次像素着色都需要读取更多数据。对于远距离或小面积物体，这不仅浪费了宝贵的显存带宽，还增加了GPU Memory Bus的负载，直接导致功耗上升和设备发热。 Cache Miss率升高：过大的纹理数据难以完全放入L1/L2缓存，导致频繁的Cache Miss，进一步引发GPU Stall（读写停滞），降低帧率。 2. 常见成因排查 未开启Mipmap：检查关键纹理资源是否在导入设置中关闭了"Generate Mip Maps"选项。 各向异性过滤（Anisotropic Filtering）强制开启：若在Quality Settings中将各向异性过滤设为"Forced On"，或在特定纹理上设置了过高等级，GPU为了修正视角倾斜带来的拉伸，会倾向于采样更高层级甚至混合多层，但在某些统计口径下，过度追求清晰度可能导致非基础层采样逻辑异常或实际仍大量依赖基础层数据。 Shader编写问题：检查是否有Shader代码强制指定了LOD层级（如tex2Dlod固定取0），或使用了不支持Mipmap采样的特殊算法。 UI纹理误用：UI元素通常不需要Mipmap，但如果3D场景中的大量贴图被错误地当作UI处理而未开启Mipmap，也会导致此现象。 3. 优化建议 合理开启Mipmap：对3D场景中的大部分纹理开启Mipmap生成。这能显著降低远处物体的采样带宽。 分级设置各向异性过滤：避免全局强制开启。建议在Project Settings中设为"Per Texture"，仅对地面、墙面等需要高质量斜视效果的纹理单独开启，并尽量使用较低等级（如2x或4x）。 控制纹理分辨率：结合渲染距离，对远景物体使用低分辨率纹理。若高分辨率纹理的Mipmap 0层采样率极低（如小于5%），说明其高分辨率部分从未被使用，应直接缩小源图尺寸。 检查RenderTexture：确认动态生成的RenderTexture是否必要开启了Mipmap，避免不必要的内存与带宽占用。 通过提升非基础层纹理的采样比例，可有效降低单次采样的数据量，从而在保证视觉质量的前提下，显著优化GPU带宽与能耗表现。 From UWA AI 问答 Q：为什么不建议用LoadFromMemory接口？ A：不建议大规模使用LoadFromMemory（含同步/异步版本）主要基于以下三方面性能缺陷，已在真实移动端项目中验证： 一、显著更高的CPU与内存开销 同步阻塞主线程：LoadFromMemory是完全同步调用，强制在主线程解压并构建AssetBundle对象，导致帧率卡顿，尤其在加载较大包（如含10张1024×1024纹理）时，耗时可达数十毫秒（对比LoadFromFile的零点几毫秒）。 双倍内存驻留：需先将完整AssetBundle字节数组（如几十MB）全部载入内存，再解压/解析；而LoadFromFile仅加载头部（KB级），资源按需流式读取，内存占用极低。 二、丧失底层IO优化能力 LoadFromFile在真机上利用系统文件句柄缓存、预读机制及OS磁盘缓存，对LZ4压缩包可直接映射解压，避免全量解压。 LoadFromMemory绕过文件系统，强制走内存拷贝+解压路径，无法享受任何OS级IO优化，且破坏Unity内部PreloadManager的加载队列与速率控制。 三、加密需求存在更优替代方案 若为防破解而加密AssetBundle，LoadFromM…

堆内存对象的Managed Size具体是如何计算的
type: item
date: 2026-02-06T12:45:00+02:00
description: 1）堆内存对象的Managed Size具体是如何计算的 2）微信小游戏项目，跑图过程场景加载比较慢如何优化 这是第464篇UWA技术知识分享的推送，精选了UWA社区的热门话题，涵盖了UWA问答、社区帖子等技术知识点，助力大家更全面地掌握和学习。 UWA社区主页：community.uwa4d.com UWA QQ群：793972859 From 问答社区 Q：在Memory Profiler观察到一个长度为9的字符串对象Managed Size为40B，显然不止每个字符2字节。请问这个应该是怎么算的？ A：堆内存对象的Managed Size可以认为是以下四个部分： 类型对象指针； 同步块索引； 专属属性（比如数组和String就有一个int32 length 4B）； 实例字段。 针对每种对象这四个部分可能都有不同，最好的办法就是直接看下源码里这个类的构造。比如String： 它就是8 (*monotor) + 8(union) + 4(length) + 2( N+1(\0) )，特殊之处就是多了个\0，相当于长度要算N+1。所以总共是22+2*N字节。 其中为什么每个对象都要额外分配类型对象指针和同步块索引，导致一定的基础占用，原理上可以参考一些官方文档或者社区文章。 《.NET 框架内部结构：CLR 如何创建运行时对象 |Microsoft Learn》 欢迎大家转至社区交流： https://answer.uwa4d.com/question/69858fdcabed2e338a7dac5e From 问答社区 Q1：目前有个点比较陌生，就是小游戏的每秒资源后台最大同时下载数量，和下载文件大小的指标比较缺失， 这块会影响玩家跑图的过程中场景加载比较慢的问题。 请问有没有官方大数据指标？ A：官方说法是小游戏资源下载并发数为10，超过时底层自动排队；单个请求文件最大不超过100MB（理论最大值，但考虑到带宽，建议单文件2~5MB以内）。 Q2：由于我们是横屏地图，真机上持续控制角色移动10秒以上，停下后，附近场景资源下载大概要等10秒才加载完整。 大概200个资源，请问有什么解决的方法？ A：这种情况看起来是没有用WXAssetBundle的接口进行AssetBundle加载，一般更推荐用这个，而不是原生的AssetBundle加载接口。WXAssetBundle的加载接口会把网上下载的东西缓存到本地，下次直接从本地加载，而且这个接口会有自动卸载的功能，总体内存占用也会更小一些。其他的优化方法就是资源设置以及打包策略的问题了。 欢迎大家转至社区交流： https://answer.uwa4d.com/question/6985999eabed2e338a7dac60 无论是社区里开发者们的互助讨论，还是AI基于知识沉淀的快速反馈，核心都是为了让每一个技术难题都有解、每一次踩坑都有回响。本期分享分别来自UWA AI问答和UWA问答社区，希望这些从真实开发场景中提炼的经验，能直接帮你解决当下的技术卡点，也让你在遇到同类问题时，能更高效地找到破局方向。 封面图来源于网络 今天的分享就到这里。生有涯而知无涯，在漫漫的开发周期中，我们遇到的问题只是冰山一角，UWA社区愿伴你同行，一起探索分享。欢迎更多的开发者加入UWA社区。 UWA官网：www.uwa4d.com UWA社区：community.uwa4d.com UWA学堂：edu.uwa4d.com 官方技术QQ群：793972859