HOME / 第 6 部分 · 数据与进阶开发 / 第 78 课
MODULE 6 · 数据与进阶开发

第 78 课 · 性能剖析与内存优化

⏱ 预计时长 40 分钟📊 难度 进阶📚 模块 第 6 部分 · 数据与进阶开发

🎯 本课学习目标

游戏卡顿?内存爆涨?本课学会用 Godot 剖析工具定位并优化。

📖 详细教学步骤

剖析器(Profiler)工具

  1. 运行游戏(F5)
  2. 编辑器底部面板切到 调试器(Debugger)→ 剖析器(Profiler)
  3. 点「开始」记录,操作一会儿游戏,点「停止」
  4. 查看各函数的耗时占比(CPU 时间)

💡 耗时最多的函数就是优化重点。

常见性能问题排查排查

现象可能原因
帧率低Draw Calls 多 / 特效重 / 脚本每帧重计算
内存涨节点没释放 / 资源重复加载 / 泄漏
卡顿瞬间同步加载 / GC / 物理大量碰撞

检查节点泄漏代码

运行时创建大量对象,若忘记释放会内存暴涨:

GDSCRIPTfunc spawn_bullet(pos: Vector2):
    var b = bullet_scene.instantiate()
    b.position = pos
    add_child(b)
    # 子弹一定要在生命周期结束时销毁!
    # 例如子弹飞出屏幕或命中后:
    # queue_free()

func check_memory():
    print("当前节点数:", get_tree().get_node_count())
    # 运行中数值持续增长 = 泄漏,要排查谁没释放

资源复用优化

避免重复加载:

GDSCRIPT# 错误: 每次调用都重新加载
func bad():
    var tex = load("res://textures/bullet.png")   # 重复加载

# 正确: 预加载一次,复用
const BULLET_TEX = preload("res://textures/bullet.png")
func good():
    use(BULLET_TEX)

减少每帧计算优化

不必要的工作别每帧做:

GDSCRIPTfunc _process(delta):
    # 错误: 每帧都创建临时数组
    # var list = get_tree().get_nodes_in_group("enemy")

    # 正确: 只在需要时更新(如每秒一次)
    timer += delta
    if timer >= 1.0:
        timer = 0.0
        refresh_enemy_list()

物理层优化优化

  • 静态物体用 StaticBody,别用大量 RigidBody
  • 关闭不需要的碰撞层检测
  • 减少物理体数量(远处物体不参与物理)
  • 碰撞形状尽量用简单形状

内存面板与调试工具

  • 调试器 → 监视器(Monitors):看 Object Count、Nodes、内存
  • 运行后回编辑器看「内存」标签
  • Web 导出时留意内存峰值
⚠️
优化没效果?

先量化再优化:剖析器确认瓶颈在哪,改完再量对比。别盲改。

⚠️
内存一直涨?

用 get_node_count 和监视器定位泄漏;检查每帧 new/instantiate 的对象是否释放。

🧪 动手试一试

🏋️ 课后练习

用剖析器找出你上一个游戏里最耗时的函数,针对它做一次优化并对比前后 FPS。

Profiler 记录 → 排序耗时 → 优化热点 → 再测。

💡

「先测量、后优化」是铁律,性能优化最忌讳拍脑袋。

💡

把 FPS 显示在屏幕上(调试用),开发期随时观察。

🎓 本课小结

性能优化:剖析器定位热点 → 常见问题(Draw Calls/泄漏/同步加载)→ 节点释放检查、资源 preload 复用、减少每帧计算、物理层优化。