Debugger.Memory¶
调试器 API 可以帮助工具通过各种方式观察被调试者的内存使用情况
它可以在分配每个新对象时用 JavaScript 调用栈对其进行标记。
它可以记录所有对象分配,生成一个 JavaScript 调用栈流,其中包含已发生分配的调用栈。
它可以计算被调试者所属项目的 *清单*,以各种方式对项目进行分类,并生成项目计数。
如果 dbg 是一个 Debugger 实例,那么 dbg.memory 的方法和访问器属性控制 dbg 如何观察其被调试者的内存使用情况。 dbg.memory 对象是 Debugger.Memory 的一个实例;其继承的访问器和方法在下面描述。
分配站点跟踪¶
如果满足以下条件,JavaScript 引擎会用分配该对象的调用栈标记每个新对象:
该对象是在某个 Debugger 实例 dbg 的被调试者的全局对象的作用域内分配的;并且
dbg.memory.trackingAllocationSites 设置为
true。一个伯努利试验成功,其概率等于所有观察到此对象在其中作用域内分配的全局对象的
Debugger实例d的 d.memory.allocationSamplingProbability 的最大值。
给定一个引用某个对象的 Debugger.Object 实例 dobj,dobj.allocationSite 返回一个保存的调用栈,指示 dobj 的引用在哪里分配。
分配日志记录¶
如果 dbg 是一个 Debugger 实例,并且 dbg.memory.trackingAllocationSites 设置为 true,那么 JavaScript 引擎会记录 dbg 的被调试者代码分配的每个对象。您可以通过调用 dbg.memory.drainAllocationsLog 获取当前日志。您可以通过设置 dbg.memory.maxAllocationsLogLength 控制日志大小的限制。
清单¶
*清单* 是对属于特定 Debugger 的被调试者的所有可达内存项的图进行的完整遍历。它会生成这些项目的计数,并按各种标准细分。如果 dbg 是一个 Debugger 实例,您可以调用 dbg.memory.takeCensus 对其被调试者的所有物进行清单统计。
Debugger.Memory.prototype 对象的访问器属性¶
如果 dbg 是一个 Debugger 实例,那么 dbg.memory 是一个 Debugger.Memory 实例,它从其原型继承以下访问器属性
trackingAllocationSites
一个布尔值,指示此 Debugger.Memory 实例是否在分配每个对象时捕获 JavaScript 执行栈。此访问器属性同时具有 getter 和 setter:对其进行赋值可以启用或禁用分配站点跟踪。读取访问器会在 Debugger 捕获对象分配的栈时生成
true,否则生成false。在新的 Debugger 中,分配站点跟踪最初处于禁用状态。赋值是可能失败的:如果 Debugger 无法跟踪分配站点,它会抛出一个 Error 实例。
您可以使用 Debugger.Object.prototype.allocationSite 访问器属性检索给定对象的分配站点。
allocationSamplingProbability
一个介于 0 和 1 之间的数字,表示应将每个新分配记录到分配日志中的概率。0 等效于“从不”,1 等效于“总是”,而 .05 则表示“二十分之一”。
默认为 1,或记录每次分配。
请注意,在多个 Debugger 实例观察全局对象作用域内的相同分配的情况下,将使用所有 Debugger 的
allocationSamplingProbability的最大值。
maxAllocationsLogLength
一次在分配日志中累积的最大分配站点数。此访问器可以被获取和存储。其默认值为
5000。
allocationsLogOverflowed
如果自上次调用 [
drainAllocationsLog][#drain-alloc-log] 以来,分配次数超过 [maxAllocationsLogLength][#max-alloc-log],并且某些数据丢失,则返回true。否则返回false。
Debugger.Memory 处理程序函数¶
类似于 Debugger 的处理程序函数,Debugger.Memory 继承存储处理程序函数的访问器属性,供 SpiderMonkey 在被调试者代码中发生给定事件时调用。
与 Debugger 的挂钩不同,Debugger.Memory 的处理程序的返回值并不重要,会被忽略。处理程序函数接收 Debugger.Memory 的拥有 Debugger 实例作为其 this 值。拥有 Debugger 的 uncaughtExceptionHandler 仍然会为 Debugger.Memory 挂钩中抛出的错误触发。
在新 Debugger.Memory 实例中,这些属性中的每一个最初都是 undefined。分配给调试处理程序的任何值必须是函数或 undefined;否则会抛出 TypeError。
处理程序函数在事件发生的同一线程中运行。它们在属于它们的区室中运行,而不是在被调试者的区室中运行。
onGarbageCollection(statistics)
刚刚完成了一个跨越一个或多个被调试者的垃圾回收周期。
statistics 参数是一个包含有关 GC 周期信息的对象。它具有以下属性
collections
collections 属性的值是一个数组。因为 SpiderMonkey 的收集器是增量的,所以完整的收集周期可能包含多个离散的收集片段,并且 JS mutator 交错运行。对于发生的每个收集片段,collections 数组中都有一个条目,其形式如下
{ "startTimestamp": timestamp, "endTimestamp": timestamp, }这里 timestamp 值是 GC 片段的开始和结束事件的时间戳。
reason
一个非常短的字符串,描述触发收集的原因。已知值包括以下内容
“API”
“EAGER_ALLOC_TRIGGER”
“DESTROY_RUNTIME”
“LAST_DITCH”
“TOO_MUCH_MALLOC”
“ALLOC_TRIGGER”
“DEBUG_GC”
“COMPARTMENT_REVIVED”
“RESET”
“OUT_OF_NURSERY”
“EVICT_NURSERY”
“FULL_STORE_BUFFER”
“SHARED_MEMORY_LIMIT”
“PERIODIC_FULL_GC”
“INCREMENTAL_TOO_SLOW”
“DOM_WINDOW_UTILS”
“COMPONENT_UTILS”
“MEM_PRESSURE”
“CC_WAITING”
“CC_FORCED”
“LOAD_END”
“PAGE_HIDE”
“NSJSCONTEXT_DESTROY”
“SET_NEW_DOCUMENT”
“SET_DOC_SHELL”
“DOM_UTILS”
“DOM_IPC”
“DOM_WORKER”
“INTER_SLICE_GC”
“REFRESH_FRAME”
“FULL_GC_TIMER”
“SHUTDOWN_CC”
“USER_INACTIVE”
nonincrementalReason
如果 SpiderMonkey 的收集器确定无法增量收集垃圾,并且必须一次性执行完全 GC,则这是一个简短的字符串,描述它确定完全 GC 必要的理由。否则,将返回 null。已知值包括以下内容
“GC 模式”
“malloc 字节触发”
“分配触发”
“请求”
gcCycleNumber
GC 周期的“编号”。不对应于已运行的 GC 周期的数量,但保证单调递增。
Debugger.Memory.prototype 对象的函数属性¶
内存使用分析揭示实现细节
内存分析可能会产生令人惊讶的结果,因为对内容 JavaScript 透明的浏览器实现细节通常会对内存消耗产生可见的影响。Web 开发人员需要了解其页面在真实浏览器上的实际内存消耗,因此工具公开这些行为是正确的,只要以有助于开发人员做出有关自身代码决策的方式进行即可。
本节介绍 Firefox 的实际行为与 Web 平台指定行为之间存在差异的一些领域。
对象¶
SpiderMonkey 对象通常使用的内存少于天真的“具有属性的属性表”模型所暗示的。例如,许多对象通常具有相同的属性集,只有属性值在各个对象之间有所不同。为了利用这种规律性,具有相同属性集的 SpiderMonkey 对象可以共享其属性元数据;只有属性值直接存储在对象中。
如果活动索引集密集,则数组对象也可以被优化。
字符串¶
SpiderMonkey 有三种字符串表示形式
普通:字符串的文本计入其大小。
子字符串:字符串是其他字符串的子字符串,并指向该字符串以进行存储。这种表示形式可能会导致一个小字符串保留一个非常大的字符串。但是,字符串本身消耗的内存是一个小的常数,与它的大小无关,因为它是对较大字符串、起始位置和长度的引用。
字符串连接:当被要求连接两个字符串时,SpiderMonkey 可能会选择延迟复制字符串数据,并将结果表示为指向这两个原始字符串的指针。同样,这样的字符串保留其他字符串,但字符串本身消耗的内存是一个小的常数,与它的长度无关,因为它是一对指针。
SpiderMonkey 会在适当的时候将字符串从更复杂的形式转换为更简单的形式。这样的转换通常会增加内存消耗。
SpiderMonkey 在所有网页和浏览器 JS 之间共享一些字符串。这些共享的字符串称为原子,不包含在字符串计数的统计中。
脚本¶
SpiderMonkey 采用了一种复杂、混合的 JavaScript 代码表示形式。内存中保留了四种表示形式
源代码。SpiderMonkey 保留了大多数 JavaScript 源代码的副本。
压缩源代码。SpiderMonkey 会压缩 JavaScript 源代码,并在需要时解压缩。启发式算法决定保留未压缩代码的时间。
字节码。这是 SpiderMonkey 对 JavaScript 的解析表示。字节码可以直接解释,或用作即时编译器的输入。源代码按需解析为字节码;从未调用的函数永远不会被解析。
机器码。SpiderMonkey 包括几个即时编译器,每个编译器都将 JavaScript 源代码或字节码转换为机器码。启发式算法决定编译哪些代码以及使用哪个编译器。机器代码可能会响应内存压力而被丢弃,并在需要时重新生成。
此外,SpiderMonkey 还会跟踪变量和对象属性中出现了哪些类型的值。这些类型信息可能很大。
在统计中,所有各种形式的 JavaScript 代码都放在"script"类别中。类型信息计入"types"类别。
源元数据¶
- 从文件生成
js/src/doc/Debugger/Debugger.Memory.md
- 水印
sha256:2c1529d6932efec8c624a6f1f366b09cb7fce625a6468657fab81788240bc7ae
- 变更集