13 KiB
title, source, url, date, tags
| title | source | url | date | tags | |||
|---|---|---|---|---|---|---|---|
| 四班:如何正确高效的查找游戏卡顿原因 | 知乎 | https://www.zhihu.com/question/28824284/answer/1965456096262096583 | 2026-06-10 23:01 |
|
关注 推荐 热榜 专栏 圈子 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,因此30Hz(60Hz的约数)或60Hz(与垂直同步速率一致)是仅有的合理目标帧率。
探究潜在性能瓶颈
单一指标无法完整揭示性能问题的位置及解决方案,但骁龙分析器可提供数十种指标,帮助你理解应用与硬件的交互方式。
在追踪捕获(Trace Capture)模式的截图中,以下三个重要指标可作为分析起点:
- 渲染阶段(Rendering Stage)
骁龙分析器中的“渲染阶段”指标,代表应用在GPU上的执行过程。每个数据轨道(track)都是该指标的一个子集,轨道数量会因应用而异。在下方截图中,绿色、品红色和紫色区块代表各个独立的表面(surface),而“表面”区块下方的轨道则对应相关的渲染阶段。
- GPU活动(GPU Activity)
这是一项系统级指标,用于展示CPU与GPU之间的交互情况。
- 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中内置的“原生追踪API(Native 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 千万创作者的优质提问、专业回答、深度文章和精彩视频尽在知乎。 立即登录/注册