Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

使用 ObjectDB 分析器

自 Godot 4.6 起,调试器底部面板中新增了一个 ObjectDB 分析器标签。该分析器允许你对当前 ObjectDB 的状态进行快照。ObjectDB 是一个数据库,包含所有当前在内存中分配的 Object 派生类。这对于识别内存泄漏和理解项目的内存使用情况非常有用。

此外,该工具还能够可视化对比两个快照之间的差异。你可以利用它来识别项目在经过修改后,内存使用方面是有所改善还是出现了退步(性能回退)。降低内存使用量往往能带来更好的性能表现,即使内存本身并不是当前的性能瓶颈。通过减少内存占用,你可以降低内存分配的次数,而内存分配是一项开销较大的操作,尤其是在游戏运行期间频繁进行大量分配时,对性能的影响会更为明显。

参见

请参阅何时以及如何避免为任何事情使用节点以获取有关使用更轻量级的节点备选方案的信息,这可以帮助减少项目中的内存使用。

警告

ObjectDB 分析器不会跟踪引擎或外部库使用的每一处内存。未暴露给脚本 API 的原生引擎类将不会出现在快照中。

如果你需要获取这方面的信息,建议考虑使用外部的内存分析工具。

用法

Debugger 底部面板中打开 ObjectDB Profiler 选项卡。你将进入摘要页面,此时尚未生成任何快照。

ObjectDB 分析器摘要(未生成快照)

ObjectDB 分析器摘要(未生成快照)

运行项目,然后达到你想要生成快照的时间点(例如加载关卡之后)。点击 Take ObjectDB Snapshot 在当前时间点生成快照。如果按钮显示为灰色,请先确保项目正在运行。

ObjectDB 分析器摘要(已生成一次快照)

ObjectDB 分析器摘要(已生成一次快照)

在项目单次运行期间可以生成多个快照。此外,你可以在快照列表中右键单击某个快照,对其进行重命名、在文件管理器中显示或删除它。

小技巧

在生成快照后,最好给它们重命名,起一些能清楚说明情况的描述性名字(比如 before_optimization (优化前)、 after_optimization (优化后))。不过,无论你给快照文件改成什么名字,快照生成的具体日期依然会被保存在快照文件本身里,不会丢失。

快照文件以 .odb_snapshot 为扩展名,存放在 user://objectdb_snapshots/ 目录下(具体细节可参考 Data paths )。由于这些文件与平台无关,因此可以放心地在不同设备之间进行复制和传输。

查看快照之间的差异

在至少生成两个快照后,Diff Against 下拉菜单就会可用。在这里,你可以选择另一个快照,与当前选定的快照进行比较。

ObjectDB 分析器左下角的 Diff Against 下拉菜单

ObjectDB 分析器左下角的 Diff Against 下拉菜单

随后,摘要页面将会显示这两个快照之间的差异:

在 Summary 标签页里对比两个快照的样子

在 Summary 标签页里对比两个快照的样子

这也适用于 ObjectDB 性能分析器中的其他每一个标签页,它们都会通过额外的列来展示这两个快照之间的差异。

在“类(Classes)”标签页中,你可以查看在生成快照的那一刻,每种类型的类(Class)分别创建了多少个实例:

Classes 标签页里查看单个快照的界面

Classes 标签页里查看单个快照的界面

当处于对比模式时,它会显示当前选中的快照的类实例数量(A 列),以及用于对比的那个快照的实例数量(B 列)。同时,它还会在 Delta(差值)列中显示出两者在实例数量上的具体差异。

Classes(类)标签页中正在对比的两个快照。这里,A 列是 ``second_session`` ,B 列是 ``first_session``

Classes(类)标签页中正在对比的两个快照。这里,A 列是 second_session ,B 列是 first_session

你可以在右侧列表中单击一个类,以便在检查器中查看它。

在检查器(Inspector)中查看一个被选中的类实例

在检查器(Inspector)中查看一个被选中的类实例

小技巧

在其他标签页(比如 Nodes、Objects 和 RefCounted)中,同样也可以在检查器里预览实例。

对象

Objects(对象)标签页也很类似,但它呈现数据的方式有所不同。在这里,每一个实例都会以线性的方式(即平铺的列表)被罗列出来,而不是像之前那样按类(Class)进行分组。当你选中某个对象时,你会在右侧看到它引用了哪些其他对象(即 Outbound References),以及它正被哪些对象所引用(即 Inbound References)。

这让你既可以从 "自顶向下(top-down)" 的视角来查看对象(查看某个给定对象引用了哪些其他对象),也可以从 "自底向上(bottom-up)" 的视角来查看(查看有哪些对象引用了这个给定对象)。

用 Objects 标签页顺藤摸瓜,看看对象里到底引用了啥

用 Objects 标签页顺藤摸瓜,看看对象里到底引用了啥

在上面的图片中,点击列表里的 default_font (默认字体)对象,视图就会切换到该对象的视角。由于这个对象正被许多其他对象引用着,所以这实际上就切换到了 "自底向上(bottom-up)" 的视角。

用 Objects 标签页反向追踪,看看是谁在引用这个对象

用 Objects 标签页反向追踪,看看是谁在引用这个对象

节点

接下来,Nodes(节点)标签页会展示在截取快照那一刻的场景树(scene tree)。

使用“Nodes(节点)”标签页来查看场景树

使用“Nodes(节点)”标签页来查看场景树

在差异视图(diff view)中,这个标签页尤其值得关注,因为它支持用一种更直观的方式来展示两次快照之间的差异。当你取消勾选 Combined Diff (合并差异)选项时,你就可以并排看到前后的不同之处了。

Nodes(节点)标签页中的独立差异视图

Nodes(节点)标签页中的独立差异视图

当你勾选 Combined Diff (合并差异)时,你可以看到所有的差异都被合并到了同一棵树里,其中新增的节点会用绿色高亮显示,而被移除的节点则会用红色高亮显示。

Nodes(节点)标签页中的合并差异视图

Nodes(节点)标签页中的合并差异视图

此外,你还可以在树状视图的底部查看一个‘孤立节点’(orphan nodes)的列表(也就是那些没有被挂载到场景树根节点上的节点)。因为这些节点是列在主场景树之外的,所以你可以把根节点折叠起来,这样就能更轻松地查看它们了。

ObjectDB 分析器中节点树末端的孤立节点

ObjectDB 分析器中节点树末端的孤立节点

引用计数

最后一个标签页是 RefCounted(引用计数)标签页。这个标签页和之前的 Objects(对象)标签页很像,但它的表格里会直接显示出 RefCounted 派生类的引用计数。这个表格一共有四列:

  • Native Refs(原生引用) : 指向该对象的原生引擎引用数量。

  • ObjectDB Refs(ObjectDB 引用) : 指向该对象的 ObjectDB 引用数量。

  • Total Refs(总引用) : 原生引用(Native references)与 ObjectDB 引用(ObjectDB references)的总和。

  • ObjectDB Cycles(ObjectDB 循环引用) : 检测到的循环引用数量。

在差异视图(diff view)中,如果某个 RefCounted(引用计数)实例同时存在于两个快照里,那么快照 B 的数据总是会显示在快照 A 的 上方

右侧的列表会显示所选实例的详细信息,其中包括一个引用列表,并会标明这些引用是否属于重复项。

使用 RefCounted(引用计数)标签页来查看 RefCounted 实例

使用 RefCounted(引用计数)标签页来查看 RefCounted 实例

备注

RefCounted(引用计数)标签页 不会 列出那些直接继承自 Object 的对象,因为这些对象并不使用引用计数机制。