[此文档是初定版,随时可能进行更改。]
JavaScript 内存分析器在 Visual Studio 2012 更新 1 和 Visual Studio 2013 中提供,旨在帮助你了解内存使用量和查找使用 JavaScript 为 Windows 生成的 Windows 应用商店应用程序中的内存泄漏。
JavaScript 内存分析器可以为你执行以下操作:
-
通过强调最相关的数据帮助你在应用程序中快速查找内存使用情况问题。
你将以快照摘要形式收到此数据,其显示两个快照之间的差异,并提供指向更详细视图的链接。
-
提供控制器、类型和根的视图来帮助隔离问题。
-
减少 JavaScript 堆数据中的不可操作的信息。
不是直接在应用程序代码中创建的对象将被自动筛选出来。 还可按对象名称筛选数据。
在本主题中:
运行 JavaScript 内存分析器
检查内存使用量
隔离内存泄漏
查看实时内存使用量摘要
查看快照摘要
查看快照详细信息
查看快照差异
在对象树中查找对象
筛选数据
查看共享对象引用
显示内置对象
保存诊断会话文件
将源代码与内存使用量数据关联
确定内存问题的提示
如果工作的 Windows 应用商店应用程序在 Visual Studio 中打开或安装在运行 Windows 8 或 Windows 8.1 预览版 的计算机上,则可使用内存分析器。
运行内存分析器
-
打开 Visual Studio。
-
Standard toolbar, choose Local Machine, Simulator, or Remote Machine." data-guid="47e079b68249fc5aebb6072418787081">如果从 Visual Studio 中运行应用程序,请在“标准”工具栏上的“启动调试”列表中,选择“本地计算机”、“模拟器”或“远程计算机”。
有关这些选项的更多信息,请参见从 Visual Studio 运行 Windows 应用商店应用程序。
-
在菜单栏上,选择“调试”和“性能和诊断”。
默认情况下,将分析当前启动项目。 如果要更改分析目标,请选择“更改目标”。
以下选项可用于分析目标:
-
“启动项目”。 分析当前启动项目。 如果你要在远程计算机上运行应用程序,则必须选择此选项,这是默认值。
-
“正在运行的应用程序”。 允许你从正在运行的应用程序的列表中选择应用程序。 在远程计算机上运行应用程序时,不能使用此选项。
当你无权访问源代码时,请使用此选项分析计算机上运行的应用程序的内存使用量。
-
“已安装的应用程序”。 允许你选择要分析的已安装应用程序。 在远程计算机上运行应用程序时,不能使用此选项。
当你无权访问源代码时,请使用此选项分析计算机上安装的应用程序的内存使用量。 如果要分析你自己的应用程序开发之外的任何应用程序的内存使用量,此选项也很有用。
-
-
从“可用工具”中,选中“JavaScript 内存”复选框,然后选择“启动”。
-
启动内存分析器时,可能会显示一个“用户帐户控制”窗口,要求你提供运行 Visual Studio ETW Collector.exe 的权限。 选择“是”。
与应用程序交互以测试相关的内存使用量方案并查看内存关系图,如以下各节所述。
-
按 Alt+Tab 切换到 Visual Studio。
若要查看内存分析器正在收集的数据,请选择“拍摄堆快照”。 请参见本主题后面的查看快照摘要。
以下是可帮助你更有效地使用 JavaScript 内存分析器的工作流步骤。 如果你怀疑你的应用程序有内存泄漏,这些步骤将非常有用。
-
在 Visual Studio 中打开应用程序。
-
运行 JavaScript 内存分析器。 有关更多信息,请参见运行 JavaScript 内存分析器。
-
如果有可能,请将你的应用程序置于遭遇内存泄漏之前的状态。 例如,这可能是在大型 DOM 刚要转变之前、加载特定页时或启动应用程序时。
-
切换到 Visual Studio(按 Alt+Tab)。
-
通过选择“拍摄堆快照”拍摄基线堆快照。
下图演示了一个基线堆快照示例:
若要对快照计时进行更精确的控制,请在代码中使用 console.takeHeapSnapshot 命令。
-
切换到你的应用程序并进行一些你怀疑可能导致内存泄漏的操作。
如果只是测试内存使用量而不是处理怀疑的内存泄漏,请参见检查内存使用量。
-
切换到 Visual Studio 并拍摄第二个快照。
-
切换到你的应用程序并重复你怀疑的导致内存泄漏的操作。
-
切换到 Visual Studio 并拍摄第三个快照。
下图演示了第二个和第三个快照的示例:
通过拍摄此工作流中的第三个快照,可以筛选出与内存泄漏不相关的、从基线快照到第二个快照的更改。 例如,预计可能有一些更改(如在页面上更新页眉和页脚)会造成内存使用量的更改,但可能与内存泄漏不相关。
-
使用内存使用量视图,调查从第二个快照到第三个快照在堆大小和对象计数方面的差异。 下面是一些提示:
-
如果可能,请尝试进一步隔离发生内存泄漏的期间,然后重新拍摄第三个快照。 若要进一步隔离内存泄漏,请使用 console.takeHeapSnapshot、用户标记以及分析器中提供的其他内存使用量数据。
-
若要查看差异视图中的对象植根于全局对象中的位置,以防止将其作为垃圾回收,请打开对象的快捷菜单,然后选择“在根视图中显示”。
实时内存使用量摘要视图提供了正在运行的应用程序的内存使用量图,以及所有快照摘要图块的集合。 在此视图中,可以执行拍摄快照、分析摘要信息和导航到其他视图等基本任务。 停止收集数据后,内存关系图将消失,你只能看到快照摘要视图。
内存关系图显示应用程序进程内存的活动视图,包括专用字节、本机内存和 JavaScript 堆。 内存关系图是进程内存的可滚动视图。 该窗口类似于下方所示:
Associate source code with memory usage data), an inverted triangle appears in the memory usage graph to indicate when that section of code is reached. " data-guid="809a68e01a7d2b1635f07a95d27145d6">如果你已向应用程序代码中添加用户标记(请参见将源代码与内存使用量数据关联),则内存使用量图中将出现一个倒三角形,用于指示何时到达该代码部分。
内存关系图中显示的一些内存是由 JavaScript 运行时分配的。 你无法在应用程序中控制此内存使用量。 当你拍摄第一个快照时,关系图中显示的内存使用量会增加,之后该使用量会对每个附加的快照按最低限度增加。
若要拍摄应用程序内存使用量的当前状态的快照,请从内存关系图中选择“拍摄堆快照”。 快照摘要图块会同时出现在实时内存使用量摘要(在应用程序运行时)和快照摘要(在应用程序停止时)中,它提供了有关 JavaScript 堆的信息和指向更详细的信息的链接。 如果拍摄了两个或更多快照,则快照将提供更多信息以将其数据与前一个快照的数据进行比较。
JavaScript 内存分析器会在拍摄每个快照之前强制进行垃圾回收。 这有助于确保各个运行中的结果更加一致。 |
以下是你拍摄多个快照时的快照摘要的示例。
快照摘要包括:
-
快照标题和时间戳。
-
潜在问题计数(用蓝色信息图标标记)。 此数字(如果存在)标识潜在内存问题(例如,节点未附加到 DOM)的数目。 此计数将链接到快照的控制器视图,此视图按照问题类型进行排序以突出显示潜在问题。工具提示中将显示问题的说明。
-
堆大小。 此数量包括由 JavaScript 运行时引擎添加到 JavaScript 堆的 DOM 元素和对象。 堆大小将链接到快照的控制器视图。
-
堆大小差异。 此值显示当前快照的堆大小和前一个快照的堆大小之间的差异。 如果内存增加,则该值后跟一个红色向上箭头;如果内存减少,则该值后跟一个绿色向下箭头。 如果快照间的堆大小未发生更改,则将显示文本“无更改”而不是数字。 对于第一个快照,将显示文本“基线”。 堆大小差异将链接到快照差异的控制器视图。
-
对象计数。 此计数仅显示在应用程序中创建的对象,并筛选出由 JavaScript 运行时创建的内置对象。 对象计数链接到快照详细信息的类型视图。
-
对象计数差异。 这将显示两个值:第一个值是自前一个快照以来添加的新对象的数量;第二个值是自前一个快照以来移除的对象的数量。 例如,+25 / -10 表示添加了 25 个对象,并移除了 10 个对象。 如果对象总计数增加,则此信息后面会跟一个红色向上箭头;如果对象总计数减少,则此信息后面将跟一个绿色向下箭头。 如果对象计数未发生更改,则将显示文本“无更改”而不是数字。 对于第一个快照,将显示文本“基线”。 对象计数差异链接到快照差异的类型视图。
-
在拍摄快照时屏幕的快照。
快照摘要可能显示堆大小或对象计数无更改或减少,但仍可能隐藏内存泄漏。 当新创建的对象的数量或大小小于已删除对象(例如,作为垃圾回收的结果)的数量或大小时,可能会出现此情况。 |
可以在快照详细信息视图中查看有关每个快照的内存使用量的详细信息。
从快照摘要视图中,选择一个链接来查看快照详细信息。 例如,默认情况下,堆大小链接将在控制器视图打开的情况下打开快照详细信息。
此图显示了快照详细信息的控制器视图,以及按问题类型排序的内存使用量数据,并突出显示了潜在问题。
在快照详细信息视图中,你可以通过从工具栏中选择相应的选项来按控制器、类型或根查看内存使用量数据:
-
支配者。 显示堆中所有对象的列表,按保留大小排序。 如果你从快照摘要中的潜在问题链接打开此视图,则将按问题类型对对象进行排序以突出显示潜在问题。 工具提示提供每个问题的说明。
控制器的差异视图可以帮助快速确定使用最多内存的对象。
-
类型。 显示对象的实例计数和总大小,按对象类型分组。 默认情况下,它们按实例计数排序。
-
根。 显示从根对象到子引用的对象的分层视图。 默认情况下,子节点按保留的大小列排序,最大的排在顶部。
所有三个视图都显示了类似的值类型,包括:
-
标识符。 最能标识对象的名称。 例如,对于 HTML 元素,快照详细信息显示 ID 特性值(如果使用)。
-
类型。 对象类型(例如,HTML 链接元素或 div 元素)。
-
大小。 对象大小,不包括任何引用对象的大小。
-
保留的大小。 对象大小加上所有没有其他父对象的子对象的大小。 从实用的角度而言,这是对象保留的内存量,因此,如果你删除对象,则将回收指定的内存量。
-
计数。 对象实例的数量。 此值仅显示在类型视图中。
在 JavaScript 内存分析器中,可以在快照差异视图中将一个快照与前一个快照进行比较。
在快照摘要视图中,如果拍摄了两个或更多快照,则可以通过选择差异堆大小或差异对象计数链接来查看差异快照的详细信息。
可以查看有关控制器、类型和根的差异信息。 快照差异显示添加到两个快照之间的堆中的任何对象。
此图显示快照差异中的类型视图。
在快照差异窗口中,控制器、类型和工具视图与快照详细信息窗口中的视图相同。 快照差异显示与快照详细信息相同的信息,并具有以下附加值:
-
“操作”。 显示当前快照中的对象和前一个快照中的对象之间的更改类型。 可能的值包括:
-
“已添加”。 自前一个快照以来添加的对象使用绿色进行彩色编码。
-
“已修改”。 自前一个快照以来修改的对象使用蓝色进行彩色编码。
-
“未更改”。 自前一个快照以来未更改的对象显示“未更改”或空白值。 未更改的对象不会泄漏内存。
-
“未更改 [基线]”。 未从基线快照更改的对象显示此值。 这些对象不会泄漏内存。
-
-
大小差异。 当前快照中对象的大小及其在之前的快照中的大小之间的差异,不包括任何引用对象的大小。
-
保留的大小差异。 当前快照中对象的保留的大小及其在上一个快照中的保留的大小之间的差异。 保留的大小包括对象大小加上其所有没有其他父对象的子对象的大小。 从实用的角度而言,保留大小是对象保留的内存量,因此,如果你删除对象,则你回收指定的内存量。
-
计数差异。 当前快照中的对象实例数和上一个快照中的对象实例数之间的差异。 此值仅显示在类型视图中。
若要帮助隔离具有内存问题的代码部分,可在 JavaScript 内存分析器中使用以下两条命令:
-
console.takeHeapSnapshot 采用出现在 JavaScript 内存分析器中的堆快照。 此命令是 JavaScript 控制台命令之一。
-
performance.mark 设置一个用户标记(倒三角形),该标记在应用程序运行时显示在摘要视图中的内存关系图的时间线上。 此命令采用一个描述事件并且在内存关系图中显示为工具提示的字符串参数。 此说明不能超过 100 个字符。
重复内存使用量方案时,请使用 console.takeHeapSnapshot 来加速分析。 |
如果你将这两条命令添加到应用程序中并在 JavaScript 内存分析器的外部运行应用程序,则这两条命令将引发异常。 但是,你可在使用这两条命令之前测试它们是否存在。(这两条命令在会话启动阶段的早期不存在。)若要检查是否可以安全调用 takeHeapSnapshot,请使用此代码:
if (console && console.takeHeapSnapshot) {
console.takeHeapSnapshot();
}
若要检查是否可以安全调用 performance.mark,请使用此代码:
if (performance && performance.mark) { performance.mark("message_string"); }
以下是具有多个用户标记和当前选定用户标记的工具提示的内存关系图,其中,performance.mark 字符串参数设置为“data generated”:
-
按照隔离内存泄漏中描述的工作流操作。
-
使用快照差异的控制器视图可帮助快速确定主要内存问题。
-
使用在根视图中显示可查看在内存层次结构中引用对象的位置。
-
当内存问题的原因时难以确定时,应使用各种视图(例如控制器和类型)查找共性,例如大小和对象计数不断增长的关联的对象和类型。
-
考虑临时修改代码来隔离问题。 例如,你可能希望:
-
对内存分析器使用 console.takeSnapshot 和 performance.mark 命令。(请参见将源代码与内存使用量数据关联。)
可以使用这两条命令来帮助隔离无法通过手动拍摄堆快照进行隔离的问题。
-
创建一个测试对象,并在 JavaScript 内存分析器视图(如控制器视图)中跟踪该对象。 例如,可以将一个极大对象附加到另一个对象以查明特定对象或组件是否已进行垃圾回收。
-
-
在用户导航到新页后,查找无意间保留在内存中的对象,这是导致出现内存问题的一个常见原因。 例如,URL.CreateObjectUrl 函数的使用不当可能导致此问题。
from:http://msdn.microsoft.com/zh-cn/library/windows/apps/jj819176.aspx