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
- 变更集