JetBrains Rider 2025.1 Help

分析内存分配

使用 内存分配 视图分析特定时间间隔内的分配:找出在此时间间隔内分配了哪些对象以及哪些函数分配了这些对象。 即使在分析仍在进行时,该视图也可以显示分配数据:不需要内存快照。

数据收集模式

dotMemory 可以以两种模式之一收集内存分配数据:

采样

(默认,仅限 Windows)dotMemory 收集有限的分配数据:对于每个分配对象的函数,您只能查看大致的对象大小。 无法获取对象数量的信息。

采样 模式的优点:

  • 它不会减慢被分析的应用程序。

  • 当分析器附加到已运行的应用程序时,您可以使用它。

数据不够详细,因为它基于 ETW 事件:每当分配的内存总大小超过 100KB 时,就会触发分配事件。 例如,一个线程在分析期间分配了五个 50 KB 的内存块。 在这种情况下,dotMemory 只会检测到两个 100 KB 的分配。

内存分配
完全

dotMemory 收集详细的分配数据:包括分配对象的确切大小和对象数量。

完全 模式的缺点:

  • 它会显著减慢被分析的应用程序。

  • 当分析器已附加到正在运行的应用程序时,您无法使用它。

在分析会话期间,您可以随时切换这些模式。 请注意,如果您想分析完整的分配数据,则必须在所需的时间范围内启用 完全 数据收集模式。 如果此范围包含 采样 数据的时间间隔, 内存分配 视图将仅显示采样的分配数据。

数据收集模式

如何获取内存分配数据

在任意时间间隔内分析内存分配

  1. 启动分析会话或 打开现有工作区。

  2. 根据您想获取的数据详细程度,使用 采样 或 完全 数据收集模式。

  3. 在时间线图上,选择所需的时间间隔。

  4. 单击 已分配:... MB 链接或 显示内存分配 按钮以打开 内存分配 视图。

    分析内存分配

    这将打开一个新编辑器文档,其中包含所选时间间隔的分配数据。

  5. 在文档中,选择您希望如何分析数据:按 类型 、按 方法 、按 调用树或按 子系统进行分组。

分析从会话开始到特定快照之间的内存分配

分析流量
  1. 启动分析会话或 打开现有工作区。

  2. 在 内存快照 下,找到所需的快照并单击 内存分配。

    查看内存分配快照
  3. 选择您希望如何分析数据:按 类型 、按 方法 、按 调用树或按 子系统进行分组。

分析两个快照之间的内存分配

分析流量
  1. 启动分析会话或 打开现有工作区。

  2. 在 内存快照 下,找到所需的快照,并通过单击每个快照的 添加到比较 将它们添加到 快照比较 区域。

  3. 在 快照比较 中,单击 查看内存分配。

    查看内存分配两个快照
  4. 选择您希望如何分析数据:按 类型 、按 方法 、按 调用树或按 子系统进行分组。

类型

内存分配视图

类型 视图由两部分组成: 对象列表和 回溯树。

对象列表

列表显示了在所选时间间隔内分配的对象,并按对象类型分组。 选择特定类型以查看哪些函数分配了此类型的对象。

名称

描述

类型

类型名称.

对象

相同类型对象的数量。

字节

对象的总体浅表大小(以字节为单位)。

回溯

回溯树显示了分配当前在对象列表中选定对象的所有调用树。 调用从下往上显示:调用堆栈中的最后一个调用是顶级节点。 换句话说,回溯是反转的调用树。

您可以按分配的内存量 (总计 / 自有字节) 或分配的对象数量 (总计 / 自有对象) 对树进行排序。 要切换排序,请单击 总计 / 自有 ... 列标题。

总计 / 自有 ... 列显示了在特定调用树 (总数) 或特定调用 (自有) 中分配的内存(对象)数量。

例如:

回溯

set_Capacity 方法分配了 149.80 MB(自有)。 该方法从两个调用堆栈中被调用:

  • 通过 AddWithResize 方法:142.69 MB

  • 以及通过 EnsureCapacity 方法:7.11 MB

要查看特定方法在 调用树 中的调用位置,请右键单击该方法并选择 在“调用树”中显示此方法的出现位置。 这将显示包含所有方法调用合并的调用树。

方法

按方法分析内存分配

方法 视图由三部分组成: 方法列表、 回溯树和前五种分配对象类型的旭日图。

方法列表

列表显示了在所选时间间隔内被调用的方法。 选择特定方法以查看该方法分配的对象类型以及方法的回溯树。 请注意,列表中的每个方法都是唯一的——它代表了从所有调用堆栈中对该方法的所有调用。

名称

描述

方法

方法名称.

对象

方法调用分配的对象数量。

字节

对象的总体浅表大小(以字节为单位)。

回溯

回溯树显示了调用当前在方法列表中选定方法的所有调用堆栈。 调用从下往上显示:调用堆栈中的最后一个调用是顶级节点。 换句话说,回溯是反转的调用树。

“Back Traces” 树与 Types 视图中的树类似。

调用树

按调用树分析内存分配

调用树 视图显示了选定时间间隔的调用树。 如果某个调用分配了对象,对象类型将显示在调用下方的树中。

总计 / 自有 ... 列显示了在特定调用树 (总数) 或特定调用 (自有) 中分配的内存(对象)数量。

您可以按分配的内存量 (总计 / 自有字节) 或分配的对象数量 (总计 / 自有对象) 对树进行排序。 要切换排序,请单击 总计 / 自有 ... 列标题。

要过滤调用树,请在窗口顶部的 搜索 搜索字段中开始输入。 了解更多关于如何设置过滤器的信息

要查看特定方法的子系统,请右键单击该方法并选择 显示此方法的子系统。

子系统

子系统

子系统将所有属于特定类型、命名空间或程序集的方法分组。 要切换分组类型,请使用表格顶部的 类型、 命名空间 和 汇编 按钮。 使用 子系统 视图可以快速了解特定应用程序组件分配了多少内存。 例如,此视图对于评估新添加或重构代码的内存分配特别有用。

每个子系统都包括其整个调用子树 (总数 大小) 创建的所有对象。 例如,在控制台应用程序中,类型 程序 的子系统将包括应用程序创建的所有对象,因为 Program.Main() 是应用程序调用树中的顶级节点。

子系统 是一个主从视图。 在左侧表格中选择一个子系统,右侧您将看到:

  • 由选定子系统的实例分配的前五种类型。

  • 选定子系统分配内存最多的前五个方法。

  • 选定子系统的合并调用树。

    如果某个调用分配了对象,对象类型将显示在调用下方的树中。

    总计 / 自有 ... 列显示了在特定调用树 (总计) 或特定调用 (自有) 中分配的内存(对象)数量。

    您可以按分配的内存量 (总计 / 自有字节) 或分配的对象数量 (总计 / 自有对象) 对树进行排序。 要切换排序,请单击 总计 / 自有 ... 列标题。

    要查看特定方法在应用程序调用树中的位置,请右键单击该方法并选择 在“调用树”中显示此方法。

从范围中排除子系统

一个应用程序包含许多不需要进一步分析的子系统。 例如,很明显, System.Windows.Application 类型的子系统将包括在分析会话期间进行的所有调用,因为应用程序是由 Application.Run() 方法启动的。 在这种情况下,您可以排除不想分析的子系统。

从分析中排除子系统

  1. 在列表中选择一个子系统。

  2. 按 删除 或右键单击子系统并在上下文菜单中选择 从范围中排除。

  3. dotMemory 会将排除的子系统变灰并将其放到子系统列表的末尾。

将排除的子系统返回

  1. 滚动到子系统列表的末尾。

  2. 选择排除的子系统。

  3. 按 删除 或右键单击子系统并在上下文菜单中选择 返回范围。

过滤结果

您可以过滤掉对分析无关的项目。

缩小列表范围

  • 在 搜索 搜索字段中开始输入所需的搜索模式。

    dotMemory 会排除所有与模式不匹配的项目。

您可以通过使用以下提示使搜索更高效:

  • 使用 CamelHumps。 例如, fo 将返回 System.Drawing.Font 和 MS.Utility.FrugalObjectList 类型的对象。

  • 使用 特殊符号 ,例如通配符和其他符号。 完整列表显示在下表中。

Symbol

描述

示例

*

通配符

*
集合中的所有对象

sys.*.data
所有匹配模式的类型和命名空间。 例如, System.Data、 System.Windows.Controls.Datagrid 和 System.Windows.Data.Binding。

sys.*.data.
仅匹配模式的命名空间。 例如 System.Windows.Data.Binding ,但 不是System.Windows.Controls.Datagrid。

数组

[]

仅保留数组

str[]
包含 str 的类型或命名空间中的数组。 例如 字符串[]。

[,
[,,
...
或
[,]
[,,]
...

仅保留指定维度或更高维度(如果括号未闭合)的数组

str[,,
包含 str 的类型或命名空间中维度为 3 或更高的数组。 例如 字符串[,,] 和 字符串[,,,]。

str[,,]
包含 str 的类型或命名空间中的三维数组。 例如 字符串[,,]。

!a

从结果中排除数组

!a str
包含 str 的类型或命名空间中(不包括数组)的对象。 例如 字符串 ,但 不是字符串[]。

有序数组

[N..
[N..]
[N..M]
[N..M, X..Y]
... 其中 N、 月、 X、 Y 是整数。

仅保留具有指定元素数量的数组

byte[10..100]
包含 Byte 的类型或命名空间中具有 10 - 100 个元素的数组。 例如 Byte[98]。

byte[10..100, 25..
包含 Byte 的类型或命名空间中第一维具有 10 - 100 个元素且第二维具有超过 25 个元素的二维(或更多维)数组。 例如 Byte[98, 30, 1000] ,但 不是Byte[98]。

如果未指定范围,则过滤器被视为文本过滤器。 例如, byte[1 将匹配 Byte[195] 和 Byte[1, 50]。
byte[1*5] 将匹配 Byte[13853]。

泛型类型参数

<

仅保留具有泛型类型参数的类型

str<
仅包含 str 的类型或命名空间并具有泛型类型参数的对象。 例如 FileStreamStorage<Char> ,但 不是List<String>。

<str
仅包含 str 的泛型类型参数中的对象。 例如 List<String> ,但 不是FileStreamStorage<Char>。

<,
<,,
...
或
<,>
<,,>
...

仅保留具有指定数量泛型类型参数的对象

fun<,,>
包含 有趣吗 的类型或命名空间并具有三个泛型类型参数的对象。 例如 Func<String, Object, Object>。

fun<str,,task
包含 有趣吗 的类型或命名空间并具有三个或匹配模式的泛型类型参数的对象。 例如 Func<Stream, IAsyncResult, TaskResult, EventArgs>。

!g

从搜索范围中排除泛型类型参数

!g str
包含 str 的类型或命名空间中(不具有泛型类型参数)的对象。 例如 字符串 ,但 不是List<String>。

#c
#结构体
#分钟
#ns

按类型、值类型、方法或命名空间搜索。

#ns Feature
包含 功能 的命名空间中的对象。

2025年 7月 31日