本文是《Unity 游戏为什么发烫》系列的第 1 篇(共 8 篇)。本篇讲清楚整个系列的底层逻辑,后面 7 篇逐个收拾"惯犯"——完整目录在文末。
一、先说结论:热量的大头,来自"搬数据"而不是"做计算"
很多开发者对功耗的直觉是:计算越多越耗电。这个直觉在 PC 上大致成立,但在手机上,真正的耗电大户常常是另一件事——内存搬运(带宽)。
原因很简单:
计算是在芯片内部完成的——数据进了寄存器和缓存,运算本身效率很高;
搬运要跨芯片——CPU/GPU 每读一次内存、每写一次帧缓冲,电流都要在芯片和 LPDDR 之间跑一个来回,这是实打实的功耗。
所以业界才有一句老话:一次内存访问的耗电,够 ALU 算几十次。你的游戏之所以烫,很可能不是 GPU 在疯狂计算,而是它在疯狂地"搬砖"。
这不是我瞎说。Arm 官方在《Mali-G51 Performance Counters Reference Guide》里给过一个可以直接拿来用的硬数字:
外部 DRAM 访问的功耗大约是每 GB/s 消耗 80–100 毫瓦。假设 DRAM 访问的典型功耗预算是 650mW,那么一款 60fps 的游戏,每帧可持续使用的总数据量只有约100MB。
翻译成人话:带宽每多用 1 GB/s,功耗就多付 80–100mW。"降带宽"和"降功耗"在移动端基本是同义词。这条数字也解释了为什么本文把"搬运"而不是"计算"当作发烫的主叙事——它是整个系列的物理基础。
二、带宽:被大多数独立开发者忽视的指标
先补一个基础概念。带宽(Bandwidth)指 GPU 与内存之间数据通道的吞吐量,单位是 GB/s——它不是"存储空间",而是"搬运速度"。
| 概念 | 说的是什么 | 类比 |
|---|---|---|
| 内存容量 | 能存多少数据 | 仓库面积 |
| 带宽 | 每秒能搬多少数据 | 马路每小时能过多少车 |
| 延迟 | 一次往返要多久 | 单程耗时 |
手机是 SoC 集成芯片,CPU 和 GPU 共享一块 LPDDR,带宽天生就窄,而且每一次搬运都直接转化成电量和热量。这就是"越玩越烫"的物理基础。
那么,你的游戏里是谁在疯狂搬运数据?三个惯犯:
惯犯 1:Overdraw(过度绘制)
全屏半透明遮罩、粒子特效、全屏后处理——每一个都会让同一块像素被反复着色。而画一个透明像素 = 从帧缓冲读出旧颜色 + 混合计算 + 写回新颜色,全是搬运。Overdraw 叠 4 层,这块搬运量就乘 4。
最典型的就是"新手村弹窗"式的 UI:
全屏黑色遮罩(整屏 ×1)
遮罩下还有一张全屏渐变背景(整屏 ×2)
弹窗面板本身半透明(×3)
文字底下又垫半透明高亮底(×4)
再叠一层全屏 Color Grading(×5)
肉眼看是一幅画,GPU 实际画了五遍。每一遍,都是整屏像素的读写搬运。
惯犯 2:未压缩 / 过大的纹理
片元着色器每输出一个像素,基本都要去内存读纹理。一张 2048×2048 的 RGBA32 纹理,一个像素 16 字节——如果压成 ASTC 6×6,能降到约 1/9。也就是说,同一张图,未压缩版本的"搬运功耗"是压缩版的 9 倍,而画面在手机屏幕上未必看得出区别。
很多团队纹理导入设置用默认值一把梭,等于让手机全程扛着最重的砖。
惯犯 3:过长的后处理链
Bloom、景深、Color Grading、暗角……URP 里随手挂一堆 Volume 效果很爽,但每加一个全屏 pass,整屏像素就多读写一遍。在 PC 上这叫"画面高级",在手机上这叫"电热丝"。
这三个惯犯是"搬运型"发热的代表,也是 GPU 侧问题的主力——但别误会,发热的锅 GPU 只背一半。完整的账本见下一节。
三、完整的敌人名单:七大热源
把一款 Unity 手游的发热原因全部摊开,可以归成七类(本篇只展开 GPU 侧,其余各篇逐一收拾):
| # | 热源 | 一句话 | 详细拆解 |
|---|---|---|---|
| 1 | GPU 渲染与带宽 | Overdraw ×N、未压缩纹理、后处理链 | 本文 + 第 3、4 篇 |
| 2 | 实时光照与阴影 | 实时光源数、阴影分辨率、实时反射——静态场景全烘焙常能砍掉一半 GPU 功耗 | 第 6 篇 |
| 3 | CPU 逻辑与 GC | Update 空转、每帧分配、GC 尖峰全核扫描 | 第 5 篇 |
| 4 | Draw Call 与物理 | DC 提交成本、FixedUpdate 50Hz、无 LayerMask 的 Raycast | 第 5 篇 |
| 5 | 动画与 UI 重建 | Animator 满屏评估、Canvas 动静不分触发整块重建 | 第 5 篇 |
| 6 | 帧率策略缺失 | 不锁帧、菜单满帧跑、切后台不降载 | 第 7 篇 |
| 7 | 外设与使用场景 | 网络 modem、GPS/传感器、屏幕亮度、边充边玩 | 第 8 篇 |
其中第 6 类最冤枉也最值钱——它不是"哪里慢",而是"根本没打算让它省"。这类问题的治理成本几乎为零(改一行targetFrameRate),却是很多团队从没做过的。
四、为什么是"越玩越烫",而不是"一直这么烫"?
这是最有迷惑性的部分。游戏负载从头到尾没变,为什么热量是逐渐累积的?
因为手机有一个自我保护机制:热节流(Thermal Throttling),俗称降频。
完整链条是这样的:
游戏负载高(带宽/功耗大) → 芯片持续发热,温度超过阈值 → 系统下调 CPU/GPU 频率(自我保护,防烧毁) → 频率降了,同样一帧要花更长时间 → 帧率下降,掉帧 → 如果负载不变,温度继续顶着阈值 → 继续降频……
这形成了一个恶性循环:帧率从 60 掉到 45,再掉到 30,机身越来越烫。很多玩家反馈"你这游戏优化不行,越玩越卡",开发者拿 Profiler 一查:CPU 不高啊?GPU 也不高啊?——因为你测的是冷机状态,玩家烫的是热机状态。
这里有个关键的认知转换:降频是"原因",掉帧是"结果"。掉帧的原因有很多(Draw Call、GC、加载卡顿……),但"越玩越卡"这种随时间劣化的掉帧,十有八九指向降频,而降频的根源又指向功耗,功耗的根源指向带宽。一条线串到底:带宽 → 功耗 → 发热 → 降频 → 掉帧。
五、三步定位你的"发烫源"
第 1 步:先分清是哪种烫
冷机启动就烫、帧率稳定地低→ 普通性能瓶颈,直接开 Profiler 查热点(Draw Call / GC / 加载);
前几分钟流畅,之后越来越烫、越来越卡→ 降频问题,从功耗下手。
第 2 步:判断是不是带宽瓶颈(5 分钟土办法)
把 Render Scale 降到 0.5 跑一遍(URP 里改一个参数的事):
GPU 帧时间大幅下降→ 基本是带宽瓶颈(像素数是平方关系,分辨率减半,像素量降到 1/4,带宽需求随之大降);
GPU 帧时间几乎不变→ 瓶颈在别处(Draw Call 或 CPU 逻辑)。
第 3 步:看 Overdraw
Scene 视图左上角切到Overdraw 模式,画面越红的区域,像素叠加越严重。全屏一片深红?恭喜,你找到电热丝了。
六、降温清单:按性价比排序
| 优先级 | 优化项 | 做法 | 降温原理 |
|---|---|---|---|
| ★★★ | 合并全屏半透明叠加 | 遮罩和背景让美术合成一张图;不可见 UI 用SetActive(false)而不是把 alpha 设成 0 | 全屏透明层每砍一层,整屏搬运少一遍 |
| ★★★ | 纹理统一压缩 | 移动端默认 ASTC,UI 大图可适当选低档位 | 搬运量直接降到零头 |
| ★★★ | 砍后处理链 | 移动端只留 1–2 个真正提升观感的全屏效果 | 每删一个 pass,整屏读写少一遍 |
| ★★★ | 静态场景光照全烘焙 | 能烘的光全烘进 Lightmap,实时光只留必要的 | GPU 计算功耗常能直接砍半 |
| ★★ | 降低 Render Scale | 中低端机 0.75–0.85,配合升采样 | 像素数平方级下降,带宽和功耗同步降 |
| ★★ | 3D 纹理确保开 Mipmap | 检查导入设置(UI 纹理才需要关) | 采样局部性好,缓存命中率高 |
| ★★ | 主动锁帧 | Application.targetFrameRate = 45(或 30) | 牺牲峰值帧率,换发热可控、全程稳定 |
| ★ | 粒子减量 | 全屏粒子特效限流 | 减少透明像素的重复着色 |
关于锁帧多说一句:与其让 GPU 满血跑 60fps 十分钟,然后降频一路跌到 25,不如直接锁 45fps——机身温度稳得住,帧率曲线是平的,玩家体感反而更好。"稳定的中帧率"永远优于"先高后崩"。这也是为什么很多大厂手游默认锁 30 或 60 的背后逻辑:帧率是可以买"发热余量"的货币。Arm 官方优化指南对这一点也有明确背书:以更高的渲染效率运行、再把帧率限制在较低水平,GPU 能更早进入空闲,反而更省电。
七、写在最后:移动端优化的隐藏货币是电量
PC 时代我们优化的是"时间":帧时间、加载时间。到了移动端,你会发现多了一个隐藏货币——电量。每一个多余的像素着色、每一张未压缩的纹理、每一层叠加的后处理,玩家都在用电池和掌心的温度替你买单。
所以下次真机测试时,除了盯帧率,也摸一摸手机背面、看一眼电量掉得多快——你的玩家,是真的在"用体温评价你的优化水平"。
系列目录(关注我,每日持续更新)
为什么你开发的 Unity 游戏越玩越烫?(本篇)—— 热节流恶性循环与"搬运≈功耗"的总纲
带宽:GPU 的粮道在哪里堵住了 —— DRAM/带宽/延迟,以及 5 分钟定位带宽瓶颈的土办法
Overdraw:两幅一模一样的画面,帧率差一倍 —— 新手村弹窗 A/B 实战
纹理与后处理:搬运量最大的两个惯犯 —— ASTC 压缩、Mipmap 与缓存命中
CPU 不是无辜的:GC、Draw Call 与 Canvas 重建 —— 另一半功耗的账
光照烘焙:降温性价比之王 —— 一招常砍半 GPU 功耗
锁帧的智慧:拿帧率换发热余量 —— 为什么"锁帧"不是偷懒而是策略
收官:七大热源排查清单 + 功耗测量实战 —— 带走的 Checklist
参考资料
Arm《Mali GPU OpenGL ES Developer Optimization Guide》(developer.arm.com)——锁帧省电、TBDR 架构与带宽关系
Arm《Mali-G51 Performance Counters Reference Guide》(developer.arm.com)——DRAM 访问功耗 80–100mW/GB/s、60fps 每帧约 100MB 预算
Android Open Source Project《power_profile.xml》文档(source.android.com)——系统级功耗组件模型(屏幕/网络/GPS)
注:文中未标注出处的功耗占比类数字均为量级参考,具体随机型、亮度、分辨率浮动,请以自己测试机的实测为准。
一句话总结:越玩越烫,是因为你的游戏在疯狂搬运数据(Overdraw、未压缩纹理、后处理链),搬运 = 耗电 = 发热,发热触发降频,降频引发掉帧——降温要从"省搬运"下手,而不是只盯着"省计算"。下一篇,我们把这个系列的物理地基——带宽——彻底讲透。