Files
obsidian-notes/InBox/四班_知乎回答_如何正确高效的查找游戏卡顿原因.md
2026-06-10 23:01:19 +08:00

13 KiB
Raw Blame History

title, source, url, date, tags
title source url date tags
四班:如何正确高效的查找游戏卡顿原因 知乎 https://www.zhihu.com/question/28824284/answer/1965456096262096583 2026-06-10 23:01
zhihu
saved
四班

关注 推荐 热榜 专栏 圈子 New 付费咨询 故事 直答 切换模式 登录/注册 如何正确高效的查找游戏「卡顿」原因? 关注问题 写回答 登录/注册 游戏 程序员 编程 Unity游戏引擎 如何正确高效的查找游戏「卡顿」原因? 背景:我在一家创业公司,我们开发了一些独立的小游戏。最近在做的一款小游戏,使用了 Unity 引擎,在研发快要完成时,我们忽然发现:游戏偶尔会卡一下,…显示全部 关注者 206 被浏览 37,149 关注问题​ 写回答 邀请回答 好问题 1 1 条评论 分享 登录后你可以 不限量看优质回答私信答主深度交流精彩内容一键收藏 登录 查看全部 12 个回答 知秋 游戏性能优化 关注

专栏文章汇总,持续更新:

高通 Adreno GPU 最佳实践 0--汇总 - 知乎

参考Game Developer Guide - Snapdragon Game Toolkit Documentation

应用的帧率是多少?

在使用骁龙分析器Snapdragon Profiler之前你可能已经察觉到应用存在性能问题。即便尚未察觉也建议先分析应用当前的整体性能以定位性能瓶颈。

帧率是分析的理想起点。游戏的最佳运行帧率通常为30帧/秒fps或60帧/秒而虚拟现实VR和扩展现实XR应用的目标帧率有时会更高。

帧率分析需关注两个维度:

平均帧率:衡量应用的平均运行速度;

帧率稳定性:即便平均帧率接近目标值,若偶尔出现“长帧”(单帧耗时过长),仍可能达不到目标帧率。这会导致用户体验卡顿、画面异常,运动效果不流畅,此时应用亟需优化。

若应用未经优化,平均帧率可能低于目标值,无法达到理想性能水平;若已完成初步优化,平均帧率可能更接近目标,但仍会周期性出现帧率峰值波动。这些波动会影响动画流畅度,因此需要定位问题根源并修改代码,以实现帧率平稳。

无论上述哪种情况骁龙分析器都能直接显示应用的实时帧率性能。下方截图中浅蓝色线条代表平均帧率数值为42.022帧/秒。

虽然42帧/秒的平均帧率可能勉强可用但蓝色线条实时帧率会周期性降至37.322帧/秒的低点。这表明应用存在丢帧现象,会对性能造成负面影响。

另需注意应用应选择与平台垂直同步Vsync速率成“约数”或“倍数”的帧率作为目标。由于多数平台的垂直同步速率为60Hz因此30Hz60Hz的约数或60Hz与垂直同步速率一致是仅有的合理目标帧率。

探究潜在性能瓶颈

单一指标无法完整揭示性能问题的位置及解决方案,但骁龙分析器可提供数十种指标,帮助你理解应用与硬件的交互方式。

在追踪捕获Trace Capture模式的截图中以下三个重要指标可作为分析起点

  1. 渲染阶段Rendering Stage

骁龙分析器中的“渲染阶段”指标代表应用在GPU上的执行过程。每个数据轨道track都是该指标的一个子集轨道数量会因应用而异。在下方截图中绿色、品红色和紫色区块代表各个独立的表面surface而“表面”区块下方的轨道则对应相关的渲染阶段。

  1. GPU活动GPU Activity

这是一项系统级指标用于展示CPU与GPU之间的交互情况。

  1. CPU调度“Trace Kernel - Sched CPU”

同样是系统级指标可概览应用在每个CPU核心上的执行状态。通过该指标你能查看应用的不同模块在哪个核心上运行以及是否存在调度问题或线程竞争问题。

借助上述指标可探究性能可能受限的三个核心领域GPU、CPU 和 垂直同步Vsync即显示器的垂直同步刷新机制

受GPU限制的应用GPU-bound application

对于图形密集型应用建议优先排查是否受GPU性能限制。

在骁龙分析器的实时视图Real-Time view“GPU利用率GPU % Utilization”是核心指标。下方第一张截图显示GPU利用率在26%-38%之间波动:

对比下方第二张截图——GPU利用率稳定在98%-100%

后者强烈表明应用正受GPU性能限制即GPU处理能力不足成为性能瓶颈

除实时视图外骁龙分析器的追踪捕获模式也能提供参考依据若应用不受GPU限制GPU活动轨道中可能会出现“空闲间隙”无GPU任务执行的时间段如下所示

若应用受GPU限制则GPU执行可能会延迟且GPU可能处于持续渲染表面的状态如下所示

受CPU限制的应用CPU-bound app

若应用不受GPU限制则需进一步判断是否受CPU性能限制。

与GPU受限不同实时视图中的“CPU利用率CPU % Utilization”并非判断应用是否受CPU限制的可靠指标。

第一张图中应用的平均CPU利用率为16%第二张图为23%。实际上第一张图中的应用是受CPU限制的但两者的利用率差异远不如GPU受限场景中那么显著因此单看利用率可能误以为应用不受CPU限制。

判断应用是否受CPU限制有两个核心标准

应用不受GPU限制 平均帧时间超过16毫秒对应60帧/秒的目标帧率1秒÷60≈16.67毫秒)。

此外还需结合应用的多线程特性及CPU架构综合判断。除“CPU利用率”外分析“CPU频率”“线程调度”等指标也会对排查有帮助。

在下方追踪捕获模式的截图中“Sched CPU 6”即第6号CPU核心上的线程似乎成为了CPU的性能瓶颈

下一步需深入分析该线程定位“热点函数”执行耗时较长的函数并判断是否可通过多线程优化。骁龙分析器的采样捕获模式Sampling capture mode 可按固定时间间隔对CPU程序计数器进行采样识别CPU的“热点执行路径”。该模式会以统计形式展示CPU活动包括在每个函数和库中花费的时间从而帮助你找到代码中执行耗时最长的函数。

下方采样结果展示了CPU上用于渲染布料纹理的“函数列表”及“函数调用顺序”。红色和橙色区块代表应用代码中的热点即执行耗时最长的部分

在本案例中CPU采样结果显示SatisfyConstraints()是最大的热点函数占用了98%的CPU活动时间。

若需进一步深入分析骁龙分析器支持“用户标记user markers”和Android NDK中内置的“原生追踪APINative Tracing API”。Android开发者可通过该API在应用代码中插入追踪标记随后在骁龙分析器中查看相关数据。

在下方示例中可使用android/trace.h对SatisfyConstraints()调用进行插桩instrument并追踪到该函数的调用源自“主线程”一个工作线程函数

渲染帧中的某一纹理,需为每块布料调用一次该函数,并根据耗时动态调整执行频率。当修改应用代码,将该函数的执行分配到多个线程后,骁龙分析器可同时显示所有活动的“完整关联视图”:

此时布料计算已在多个线程中并行执行。从“CPU调度”指标可看到更多线程活动应用不再受CPU限制CPU会等待绘制任务的分发而非因CPU能力不足导致绘制延迟

以上流程是使用骁龙分析器识别、诊断并解决性能问题的典型案例。

受垂直同步限制的应用Vsync-bound app

若确定应用既不受CPU限制也不受GPU限制则可能受垂直同步Vsync限制——即应用的运行速度已达到显示硬件的最大刷新能力。在骁龙分析器的追踪捕获模式中可能会看到类似下方的画面

需注意此时单帧时间恰好约为16毫秒对应60帧/秒1秒÷60≈16.67毫秒且在帧周期末尾会出现一段“间隙”——期间CPU和GPU均处于等待状态等待可用的表面surface以进行下一帧渲染。

尽管许多应用的目标是“尽可能达到显示硬件的最大刷新速度”,但即便应用受垂直同步限制,仍存在优化空间,且优化收益不仅限于提升帧率。

移动应用的多数性能问题最终都与“功耗/电池续航”相关。即便应用通过“受垂直同步限制”而非受CPU或GPU限制达到了目标帧率仍建议优化代码若能通过修改代码降低功耗、减少设备发热应用可在“完成更少工作”的同时维持目标帧率还可能在低端设备上实现更优性能。

阅读全文​ 赞同 72 添加评论 314 7 分享 豆包让小白也能玩转 AI 漫画图片生成 豆包让小白也能玩转 AI 漫画图片生成 查看详情 豆包 的广告 更多回答 王耀威 投资合作做游戏找我 关注

首先打开profiler,查看所有凸起的线

一般游戏内卡顿的地方

游戏战斗过程中在加载资源文件 NGUI中图集太乱导致drawcall彪涨

NGUI中active/unactive导致重建drawcall生成大量的资源 频繁创建对象删除对象,没有缓存。 unity自身的一些bug,有时候可以看到物理引擎计算的量很大。 使用了更精确但更耗时的判断如meshcollider 所有逻辑都使用unity主线程处理 使用过多复杂的渲染如一些实时GI或摄像机渲染效果加强 string串接foreach,getcomponet等问题

解决方法

在游戏战斗开始时前加载所有用到的资源不要在战斗过程加载资源因为unity是单线程的模式如果没有使用异步线程做加载或一开始进入场景时加载这个问题就很突出了。

NGUI为了减少GPU状态切换的消耗比如切换material把相同material的UIWidget合并减少Draw Call的数量。这一步是基于UIPanel做的合并UIWidget的代码可自行查看UIPanel.cs的FillAllDrawCalls()函数,原理如下图,尽量分好层次如背景框,按钮等。 NGUI中active/unactive会删除重建材质drawcall,如果界面内容稍多一些会导致内存分配甚至出现drawcall的死循环目前比较正确的做法是设置在屏幕坐标外部然后关闭所有NGUI脚本的运行NGUI作者的回复截图。

使用对象池缓存一部分频繁使用的资源,不必每次都创建卸载。 更新新版本,设置好物理引擎参数。 如果没有必要的话尽量使用速度较快的碰撞检测入boxcollider。 应该合理分离主线程与逻辑线程的关系比如一些算法采用异步执行的方式网络数据的解析加载等使用代理来把必要的逻辑切换到主线程不必要的逻辑使用逻辑线程可以通过一个MonoBehaviour的update来执行代理逻辑 有些手机根本无法运行复杂的渲染,能简单尽量简单。 字符串串接使用stringbuilder不使用+频繁foreach最好用for代替缓存已经取到的componet. 阅读全文​ 赞同 30 6 条评论 59 11 分享 知乎用户

分享一点我们自己在做性能优化时的小经验:

在Unity Editor模式下运行有部分Overhead是由运行时的场景编辑器导致的采样的时候可以先把“Scene”关掉。

用Profiler采样时首先重点关注CPU占用率高的方法并且优先打击

关注内存分配“GC Alloc”每帧超过100B的内存分配都需要解决否则这样的的内存分配累积后就会引起GC很容易引起卡顿

发布于2015-03-18 11:59 赞同 11 9 条评论 19 3 分享 查看全部 12 个回答 下载知乎客户端 与世界分享知识、经验和见解 广告 关于作者 知秋 游戏性能优化 回答 21 文章 33 关注者 243 关注他 发私信 大家都在搜 换一换 清北鹅腿阿姨被曝卖鸭腿 421 万 热 2026 高考数学 349 万 热 我国灵活就业人数超 3 亿 347 万 热 黄仁勋自嘲亚洲家庭关系 343 万 热 香港火灾落案起诉七人及两家公司 336 万 新 重回高考那年还能做对几道 329 万 热 膳魔师致 3 人失明 316 万 热 钉钉副总裁发表长文《置身钉外》 315 万 热 运城多人被臭味熏醒 300 万 热 闲鱼 8 元出售少女裸照 251 万 热 广告   帮助中心 服务热线400-919-0001 帮助与客服 联系我们 更多   举报中心 违法和不良信息举报010-82716601 我的举报 更多   关于知乎 知乎个人信息保护指引 知乎协议 下载知乎 Investor Relations 网站资质信息 更多 京ICP证110745号 · 京ICP备13052560号-1 · 京公网安备 11010802020088 号 · 京网文[2025]0422-132 号 · 药品医疗器械网络信息服务备案网药械信息备字2022第00334号 登录即可查看 超5亿 专业优质内容 超 5 千万创作者的优质提问、专业回答、深度文章和精彩视频尽在知乎。 立即登录/注册