JetBrains Rider 2025.2 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.FontMS.Utility.FrugalObjectList 类型的对象。

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

Symbol

描述

示例

*

通配符

*
集合中的所有对象

sys.*.data
所有匹配模式的类型和命名空间。 例如, System.DataSystem.Windows.Controls.DatagridSystem.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]
... 其中 NXY 是整数。

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

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
#结构体
#m
#ns

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

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

最后修改日期: 2025年 9月 26日