UWA问答 | 博客 | 游戏及VR应用性能优化记录分享 | 侑虎科技
type: channel
link: https://blog.uwa4d.com/
description: UWA博客，UWA旗下官方博客。针对游戏及VR应用性能优化等内容记录、交流，以及案例分享。博客主要分为：厚积薄发、万象更新、博观约取、充电一刻、博物纳新等几个模块。
items: 系统层显存 vs 引擎层显存的差值从哪来
items: UE5 Chaos物理｜创建物理世界对象
items: 不用死磕 Insights，也能定位UE性能瓶颈
items: 3 月刊｜GPM 2.0 性能数据探索 & 单玩家追踪升级，精细化性能分析再突破
items: 小游戏的Spine数量过多开销大
items: Unity移动端游戏性能优化简谱之 功耗、发热和降频在软件层面的优化
items: Unity移动端游戏性能优化简谱之 以模块思维划分的CPU耗时调优（下）
items: 如何兼顾大量小怪渲染时的合批性能和层次感
items: Unity移动端游戏性能优化简谱之 分门别类地控制运行时内存（下）
items: UE5版本中GC的改动

系统层显存 vs 引擎层显存的差值从哪来
type: item
date: 2026-04-10T08:50:00+03:00
description: 1）系统层显存 vs 引擎层显存的差值从哪来 2）如何定位String的异常增长 这是第470篇UWA技术知识分享的推送，精选了UWA社区的热门话题，涵盖了UWA问答、社区帖子等技术知识点，助力大家更全面地掌握和学习。 UWA社区主页：community.uwa4d.com UWA QQ群：793972859 本次推送的实战案例来自于使用UWA服务的项目的真实且典型的问题。UWA将关键线索、定位路径与处理建议整理成了可复用的案例笔记，便于大家快速对照、排查自身项目中的同类问题。 实战案例 Q：我们项目中通过系统层统计到的显存有1.5GB，但是通过引擎层采集到的纹理、网格、RT这些加起来也只有400+MB，为什么会这样，其它的部分是什么呢？ A：这个其实是一种比较少见的情况，根据以往的经验来说可能有以下几种可能性： Shader占用本身是属于引擎层Native部分的，在运行中会执行Shader.CreateGPUProgram把它编译成GPU可以理解使用的一个Program，生成的这个GPU Program在一些项目中可能造成相当可观的高占用，我们在过往部分极端测试中也发现，它会同时导致系统层Native内存与GFX显存出现显著上升。 测试发现一些RT除了在Memory Profiler中统计到的部分外，也会对显存造成一些额外的开销。 在其它项目中还见过使用Compute Buffer，或者在引擎设置里面开辟一些额外的Buffer，通过C++进行加载的，也会对显存造成额外开销。 这些内存的具体来源是什么无法直接通过Unity引擎的分析工具进行分类和定位，建议可以做一些对比测试，比如去拆分一些渲染策略或场景，如果观察到开启某个渲染策略、进入某个渲染场景时显存出现明显的飙升，那么基本就能做更精准的定位了。 参考文章：《Unity移动游戏工业级性能优化指南 3.0》 实战案例 Q：我用Memory Profiler看到托管堆内存部分中String驻留了50+MB、45万多条，这个现象是正常的吗？ A：这一部分占用还是比较高的，从下图右边的Details信息看很多来自TMP图集用的文本，这种大量字符串理论上不应该驻留在运行时了，我们生成了TMP的图集纹理后像这个文本应该就不需要了，可以看看是不是可以及时卸载。 无论是社区里开发者们的互助讨论，还是AI基于知识沉淀的快速反馈，核心都是为了让每一个技术难题都有解、每一次踩坑都有回响。本期分享分别来自UWA AI问答和UWA问答社区，希望这些从真实开发场景中提炼的经验，能直接帮你解决当下的技术卡点，也让你在遇到同类问题时，能更高效地找到破局方向。 封面图来源于网络 今天的分享就到这里。生有涯而知无涯，在漫漫的开发周期中，我们遇到的问题只是冰山一角，UWA社区愿伴你同行，一起探索分享。欢迎更多的开发者加入UWA社区。 UWA官网：www.uwa4d.com UWA社区：community.uwa4d.com UWA学堂：edu.uwa4d.com 官方技术QQ群：793972859

UE5 Chaos物理｜创建物理世界对象
type: item
date: 2026-04-08T06:02:00+03:00
description: 【USparkle专栏】如果你深怀绝技，爱“搞点研究”，乐于分享也博采众长，我们期待你的加入，让智慧的火花碰撞交织，让知识的传递生生不息！ 物理系统与物理世界 物理系统是每个游戏引擎必备的功能，可以让游戏模拟真实世界的物理规则。而现代游戏引擎中的“物理”，应该称为刚体动力学。刚体（Rigidbody）是理想化、无限坚硬、不变形的固体物理。动力学（Dynamics）是一个过程，计算刚体怎样在力（Force）的影响下随时间移动及相互作用。 在游戏世界背后，有一个镜像的物理世界，其中不关心Actor的视觉表现，只关注Actor的形状、物理材质等信息。简单使用场景下，只要把所有Actor当成刚体处理即可。 以常见的StaticMeshActor为例。下图左侧是Editor窗口，右侧是Chaos Visual Debugger看到的物理世界。 UE5的物理引擎已经从PhysX改成了Chaos，可能物理查询速度会慢些，但更适合做物理破坏效果，而且数据结构和游戏引擎统一，不需要再做转换。 物理世界类 UWorld是代表由Actor构成的整个游戏世界，它持有一个FPhysScene来代表物理世界，可以类比为渲染中的FScene，物理世界的步进（Advance）初始也由UWorld::Tick()发起。UWorld与物理相关的功能一般在PhysLevel.cpp中实现。FPhysScene等价于FPhysScene_Chaos，继承自FChaosScene，是Chaos的首要入口。碰撞事件的注册分发，物理网络同步相关的内容也由其处理，物理模拟的步进也在该类开始（StartFrame）。 示例：创建一个StaticMeshComponent StaticMesh的物理配置 编辑器中，可以给StaticMesh设置碰撞，这里直接使用和模型大小一样的Box碰撞即可。还有其他很多选项，如Sphere、Capsule、凸包等，面对复杂模型时会用多种基础形状拼出一个碰撞。 UBodySetup 这些碰撞配置，最终会存储到UBodySetup类里，作为资源的一部分，它会是StaticMesh的一个配置项。对于例子中添加的简单几何体碰撞，存储在其AggGeom变量中。 class UBodySetup : public UBodySetupCore { //... /** Simplified collision representation of this */ UPROPERTY(EditAnywhere, Category = BodySetup, meta=(DisplayName = "Primitives", NoResetToDefault)) struct FKAggregateGeom AggGeom; //... }; AggGeom里是一大串几何体的数据，Box就位于BoxElems数组里。 struct FKAggregateGeom { GENERATED_USTRUCT_BODY() UPROPERTY(EditAnywhere, editfixedsize, Category = "Aggregate Geometry", meta = (DisplayName = "Spheres", TitleProperty = "Name")) TArray<FKSphereElem> SphereElems; UPROPERTY(EditAnywhere, editfixedsize, Category = "Aggregate Geometry", meta = (DisplayName = "Boxes", TitleProperty = "Name")) TArray<FKBoxElem> BoxElems; UPROPERTY(EditAnywhere, editfixedsize, Category = "Aggregate Geometry", meta = (DisplayName = "Capsules", TitleProperty = "Name")) TArray<FKSphylElem> SphylElems; UPROPERTY(EditAnywhere, editfixedsize, Category = "Aggregate Geometry", meta = (DisplayName = "Convex Elements", TitleProperty = "Name")) TArray<FKConvexElem> ConvexElems; UPROPERTY(EditAnywhere, editfixedsize, Category = "Aggregate Geometry", meta = (Dis…

不用死磕 Insights，也能定位UE性能瓶颈
type: item
date: 2026-04-03T06:00:00+03:00
description: 做UE项目的你，一定经历过这些场景：QA测出卡顿 → 录屏反馈 → 程序复现半天，对不上。打开 Unreal Insights，却发现真机数据和Editor分析结果不一致： 跨线程（GameThread / RenderThread / RHIThread）互相影响，瓶颈像“黑盒”一样难以拆解，长周期卡顿、内存泄露问题，测得到却抓不住。最后问题不是解决不了，而是——定位成本太高，效率太低。 UE性能分析长期存在一个核心断层：开发侧分析工具（Insights）与日常QA测试数据之间，无法稳定对齐，这意味着：QA的数据，程序不能直接拿来主义、分析必须反复复现、性能优化高度依赖经验与人力，仍然是一件“专家工具 + 人肉分析”的事情。 随着 Unreal Engine 5.7的发布，UWA GOT Online UE版迎来全量升级。但这次，我们做的不是简单适配，我们想做的是：把UE性能优化，从“少数人能做”，变成“团队都能做”的标准能力。 原生级引擎适配 让数据第一次真正“对齐” 从“看数据”到“直接定位问题” 我们完成了UE 5.x全系列（含5.7）的原生适配，并打通了引擎底层数据链路。具体包括： 1. 函数级Timeline与Insights的100%对齐 函数名、调用层级、时间统计完全一致，这意味着：真机数据，可以直接用于定位问题，而不是“参考数据”，程序无需再在多个工具之间反复核对。 2. 引擎原生指标全量接入 新增5大类、数十条UE原生STAT指标，譬如覆盖了渲染流程中，从FDrawSceneCommand（RT）到RHIThreadExecute（RHI），每一层都有指标 + 函数堆栈，可以精确定位：到底卡在“哪一段渲染流程”。 另有，加载/GC/动画/物理/AI/UI，所有数据均来自UE原生采集通道，开发者看到的，就是引擎真实发生的。 物理模块 UI 模块 多线程核心指标（Game/Render/RHI）全面覆盖：支持多视角切换（总览/单帧/场景） 且支持独立线程分析、冰柱图 + 堆栈联动、万级节点自动过滤。可以直接定位到某一帧、某一线程、某一个函数。 性能优化第一次变成“团队能力” 这个版本中我们也支持了一系列对于日常调试需求来说非常友好的功能，譬如： 新增Direct Mode模式，支持游戏启动后，立即开始抓取性能数据。能够针对游戏启动后加载慢、内存增长快等特殊场景进行针对排查。 编译级开关可控，支持宏定义一键屏蔽 SDK，可在 Debug、Release 等不同编译环境中灵活控制 SDK 的启用与关闭，彻底避免了 SDK 对项目正常开发、编译与发布的影响。 集成流程简化，移除 Binaries 目录，降低了项目版本管理与团队协作的成本。 这次升级里，最具行业意义的一点，QA可以参与性能定位了： 过去：QA → 发现问题 → 程序分析 → 来回拉扯 现在：QA → 直接提供可定位数据 → 程序直接修 带来的本质变化是：性能优化，从“程序能力”，变成“团队协作能力”，并且覆盖研发全周期的性能管控，从SDK接入、功能测试、性能回归、长周期监控、一套工具全部覆盖，支持 Android / iOS；不只是“跑得快”，也关注“玩家体验”。 从2015年至今，UWA始终专注于性能优化领域。但这一次，我们更在意的是另一件事：能不能把“复杂能力”，变成“标准流程”，如果你正在做UE项目，并且遇到这些问题： 性能问题定位效率低 QA与程序反复沟通 长周期问题难复现 那这次Unreal版的GOT Online，就是为你准备的。我们做的，不只是工具升级，而是让性能优化这件事，第一次可以被“团队稳定复用”。 关于UWA UWA是一家创业十年的高新技术企业，作为游戏行业的深耕者，UWA始终专注于为使用Unity、Unreal引擎的开发者提供丰富的优化产品，帮助开发者高效解决开发问题、定位性能瓶颈、提供解决方案，已支持超过一万款游戏项目。

3 月刊｜GPM 2.0 性能数据探索 & 单玩家追踪升级，精细化性能分析再突破
type: item
date: 2026-04-02T05:09:00+03:00
description: GPM 2.0持续深化全链路性能监测能力，2026年3月围绕性能对比、个体排查、分布统计、案例沉淀四大核心场景完成功能升级，推出性能汇总、数据探索、单用户数据、性能分布大盘及收藏库五大实用能力，实现版本迭代效果量化、单玩家问题快速复现、多维数据自由检索与团队经验长效沉淀，从宏观趋势研判、微观问题定位、高效协同排查三个维度，全面提升性能分析效率与决策精准度。 性能汇总 + 数据探索 多维度横向对比，量化版本迭代差异 「性能详情」模块全新上线性能汇总功能，支持多版本、多场景、多设备关键性能指标一键横向对比，有效解决版本迭代后性能波动难以量化、优化效果无法直观评估的行业痛点。用户可自定义指标展示、排序规则与统计粒度（日级/小时级），清晰呈现各维度性能表现并支持数据导出，帮助研发团队快速识别性能退化点与优化收益。 配套推出的数据探索功能，提供高度灵活的自定义分析面板，支持自由配置表格行、列、数值与筛选条件，满足多维度交叉比对需求，同时开放更自由的数据查询与导出能力，适配多样化深度分析场景。 单用户数据 精准定位个体体验问题，高效响应玩家反馈 新增单用户数据模块，包含玩家查询与条件查询两大核心能力： 玩家查询：支持通过玩家 ID、GPM ID 精准检索目标用户的全部历史会话，联动性能曲线与异常报告关键指标，快速定位该用户体验最差的会话，高效处理玩家反馈与客诉问题。 条件查询：支持按用户维度与设备、版本、环境等条件组合筛选，批量查看会话性能数据，一屏锁定存在性能短板的异常报告，大幅提升个体问题排查效率。 性能分布大盘 自定义指标与分档，全局掌握性能结构 全新性能分布大盘支持自选核心指标、自定义档位区间、配置统计周期（动态/静态），并可保存多套分析方案。单指标支持跨时段数据对比，点击分布柱状图可直接下钻至指标分析页面并自动锁定对应数据区间，帮助团队快速掌握性能分布特征，为适配优化与版本决策提供依据。 收藏库 典型案例一键沉淀，构建团队共享知识库 本次更新新增收藏库功能，针对典型卡顿、崩溃、性能拐点等高价值会话，支持一键收藏、自定义备注、问题类型标注与排查结论记录。实现典型案例长效留存与团队共享复用，避免同类问题重复排查，降低沟通与试错成本，构建可持续迭代的性能优化知识库。 立即体验！ 专属通道限时开放 ➡ 预约技术专家1V1部署指导！我们将全程支持服务搭建、数据分析与反馈，确保您能够充分体验GPM 2.0带来的价值。 邮件：sales@uwa4d.com 微信号：17502188376 了解GPM 2.0全功能，可以点击《GPM 2.0 核心功能全景指南｜重塑游戏性能主动管控能力》查看详情。 关于GPM 2.0 UWA GPM 2.0是专为上线及测试阶段游戏项目打造的高性能监测平台。它不仅能深度捕捉宏观性能数据，更创新采用性能无损截帧技术，在不影响玩家体验的前提下，助力开发者全面掌握玩家端运行关键细节，从多维度优化游戏性能，实现从“玩家投诉后救火” 到 “问题发生前预警” 的核心转变。 GPM 2.0全景指南 《UWA GPM 2.0 核心功能全景指南｜重塑游戏性能主动管控能力》 《GPM 2.0 功能更新月报：新增导出表格、崩溃反混淆等实用功能，体验再升级！》 《2 月刊｜GPM 2.0错误日志分析上线，PC端监测能力全维度突破》 《1 月刊｜日报周报一键获取+AI问答，玩家行为精准分析》 《12月刊｜上新！全局筛选+设备标记+序列帧回溯，GPM 2.0性能分析效率拉满》 GPM 2.0新功能 集锦 《GPM 2.0全新功能发布｜GPU精准监测 + 精细化运营，重构游戏性能管控新范式》 《GPM 2.0 SDK 热更新｜不打扰玩家的“隐形升级术”！》 《GPM 2.0功能尝新｜AI识图精准捕获材质丢失，全链路护航游戏品质！》 《UWA GPM 2.0 崩溃上报功能全面升级｜全场景覆盖+免费开放，让崩溃排查不再卡壳》 《大R流失、问题难复现？GPM 2.0「指标 - Session直连」功能，让异常定位效率翻倍！》 《从 “被动救火” 到 “主动掌控”：GPM 2.0 如何重塑游戏性能竞争力？》 《GPM 2.0 告警功能：游戏性能的智能守护者》 《无限接近真相｜GPM 2.0 功能上新》 《崩溃现场全回溯｜GPM 2.0「崩溃上报分析」上线，终结“无法复现”的噩梦》 《GPM 2.0 全新发布「卡顿帧堆栈」功能｜精准高效定位游戏玩家端性能》 《深入解析「卡顿帧堆栈」》 《解锁GPM 2.0「卡顿帧堆栈」｜代码示例与实战分析》 《如何精准打点解决卡牌、SLG、开放大世界、放置类游戏卡顿难题》 《不妥协每一毫秒的性能 不浪费每一字节的流量》 《GPM 2.0 重新定义性能监测与优化｜从未知到已知，从被动到主动》 GPM 2.0案例精讲 集锦 …

小游戏的Spine数量过多开销大
type: item
date: 2026-04-01T05:09:00+03:00
description: 1）小游戏的Spine数量过多开销大，怎么办 2）关于在AssetBundle中同时看到SpriteAtlas图集纹理和小图是否合理 这是第469篇UWA技术知识分享的推送，精选了UWA社区的热门话题，涵盖了UWA问答、社区帖子等技术知识点，助力大家更全面地掌握和学习。 UWA社区主页：community.uwa4d.com UWA QQ群：793972859 From 问答社区 Q1：我们小游戏上Spine耗时有点高，平均每帧耗时8.04ms，该怎么优化？ A：从函数调用次数来看，每帧有200多次调用，这个数量级下单个Spine的开销其实已经相对较低了。其中还看到SkeletonAnimation.FixedUpdate会有3~4ms的开销，理论上进入FixedUpdate后会直接Return，但由于调用数量太高（物理调用次数最大17，导致SkeletonAnimation.FixedUpdate的调用次数达到3000+），还是把这里的开销堆上去了。可以考虑禁用Skeleton Animation组件，专门写一个Manager主动触发Spine的Update和LateUpdate，应该能减少大量Spine对象导致跨语言调用开销。 Q2：是不是要重写一个Skeleton Animation组件呢？ A：在Manager里面注册Skeleton Animation到List里面，统一把SkeletonAnimation.enabled=false就好，然后用Manager统一调用Update和LateUpdate，不用重写Skeleton Animation。 Q3：是在Manager里面的Update直接getComponent到Skeleton Animation点出Update执行吗？ A：最好一开始就注册到某个List里面，动态维护这个List，在Update里面遍历这个数组，每个成员都执行Update。 欢迎大家转至社区交流： https://answer.uwa4d.com/question/69c9ec21abed2e338a7dac6d From 问答社区 Q：有个打AssetBundle的情况想咨询下， 我们把一个Unity SpriteAtlas图集打成一个包，这个包里理论上应该只有合并后的图集一个资源， 现在用AssetStudio解包看除了图集还有单个散图，是正常的吗，会不会导致运行时同时加载出来图集和小图而冗余？ A：下图是只打了一个SpriteAtlas图集的AssetBundle在AssetStudio中看到的情况。AssetBundle打包了sactx的Texture2D大图的同时，也打包了很多Sprite；只要看到小图的Type不是Texture2D，就是正常的。 Assets: - Assets/CommonAssets/AssetBundle Test/Texture_common/SpriteAtlas/TestAtlas.spriteatlasv2 Dependencies: [] 运行时还是仅加载一张大图，然后找到其中小图所在的UV位置和长宽，就渲染出来了。 欢迎大家转至社区交流： https://answer.uwa4d.com/question/69c9e6feabed2e338a7dac6c 无论是社区里开发者们的互助讨论，还是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-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…