GC 占用预期运行时间的 32%?
GC taking 32% of runtime expected?
目前正在优化库以提高速度。我已经大大减少了执行时间,使用 V8 CPU and Memory Profiling through Webstorm. This was achieved mainly by changing the core method from recursive to iterative.
现在自拍时间分布分解为
我假设第一个条目 "node" 是计时内部函数调用,这很好。其他条目也有意义。我是 Nodejs 分析的新手,但 GC 的 31.6% 似乎很高,所以我决定调查一下。
我现在已经通过 Webstorm 创建了一个堆转储,但不幸的是,这并没有给我太多信息。
这些好像主要是系统内存引用。步步走核心iteration code logic again, there also don't seem to be a lot of places where memory is explicitly allocated (using this作为参考)。
问题
- 可以减少GC开销吗?
- 这里的分配量是预期的吗?
- 是否可以获得更好的内存分析信息?
设置说明
如果有人想尝试调试它,我会提供安装说明。
下载或克隆 object-scan 和 运行
yarn install --frozen-lockfile
yarn run test-simple --verbose
现在在项目根目录中创建一个文件test.js
包含this content和运行node --trace_gc test.js
或运行它通过Webstorm进行高级分析。
在 Javascript 和 v8(节点)中,特别是垃圾收集所花费的时间取决于堆中存储的数据量,但这只是众多因素之一。
在 v8 引擎中有两个主要的 "types" GC:minor (scavenge) 和 major (mark-sweep/mark-compact)。您可能会在启用 --trace-gc
的控制台中看到测试期间发生的 GC 类型。在不同的情况下,一种类型可能比另一种类型 "eat" 更多时间,反之亦然。所以在优化之前你应该确定哪个gc需要更多的时间。
没有太多优化主要 GC 的选项,导致它受保留在内存中 "long"(实际上在这种情况下很长意味着对象在清除 GC 中幸存)期间的数据量的影响很大。此类数据存储在堆中所谓的 "old space" 中。主要 GC 使用此 space,它应该扫描所有内存并标记不再有任何引用的对象以供进一步清除。
在您的情况下,您正在加载的测试数据量变为旧 space。因此,它会影响整个测试期间的主要 GC。在这种情况下,主要 GC 不会清除太多,因为你正在使用你的测试对象,但它仍然会消耗时间来扫描整个旧 space。因此,您可以考虑通过启动带有 gc 特定标志的节点来防止 v8 执行此操作,例如:--nouse-idle-notification --expose-gc --gc_interval=100500
(其中 100500 是分配数量,它可以采用高值来防止 运行 gc 在整个测试将通过),这将允许手动触发垃圾收集。使用这种方法测试你的代码,看看主要的 GC 是如何影响它的,尝试使用你提供的不同数据量进行测试。如果影响不大,您可以尝试重构您的代码,尽量减少长期变量、闭包等。
如果你会发现major GC对性能影响不大,那么scavenge GC占用的时间最多。与主要 GC 不同,它在堆中使用所谓的 "new space" 进行操作。这是一个 space 存储所有新对象的地方。如果这些对象在清除后幸存下来,那么它们将被移动到旧 space。新 space 的大小(您可以通过设置 --max_semi_space_size
来控制它,注意:new space size = 2 * semi space size
)比旧的 space 和更多的新对象和变量分配更多的清除 GC 运行会发生。如果此 GC 过度加热性能,您可以考虑重构您的代码以减少新分配。但是,如果您将重用变量,它也可能会降低性能,并且这些对象将变旧 space 并可能成为 "major GC" 部分中描述的问题。
此外,v8 GC 并不总是在您的程序运行的同一线程中工作。它也在后台做一些工作,但我不知道 Webstorm 在你的案例中显示了什么。如果它只计算在 GC 上花费的总时间,可能只是没有那么大的影响。
您可以在 blog post.
中找到有关 v8 GC 的更多详细信息
长话短说:
Can the GC overhead be reduced?
- 是的,但首先您应该按照上述步骤发现应该优化的内容。
Is this amount of allocation just expected here?
- 这可以通过比较不同的方法来发现。没有绝对数字可以限制 "bad" 的 "good" 数量,因为它取决于很多因素,包括输入数据的数量。
Is it possible to get better memory profiling information?
目前正在优化库以提高速度。我已经大大减少了执行时间,使用 V8 CPU and Memory Profiling through Webstorm. This was achieved mainly by changing the core method from recursive to iterative.
现在自拍时间分布分解为
我假设第一个条目 "node" 是计时内部函数调用,这很好。其他条目也有意义。我是 Nodejs 分析的新手,但 GC 的 31.6% 似乎很高,所以我决定调查一下。
我现在已经通过 Webstorm 创建了一个堆转储,但不幸的是,这并没有给我太多信息。
这些好像主要是系统内存引用。步步走核心iteration code logic again, there also don't seem to be a lot of places where memory is explicitly allocated (using this作为参考)。
问题
- 可以减少GC开销吗?
- 这里的分配量是预期的吗?
- 是否可以获得更好的内存分析信息?
设置说明
如果有人想尝试调试它,我会提供安装说明。
下载或克隆 object-scan 和 运行
yarn install --frozen-lockfile
yarn run test-simple --verbose
现在在项目根目录中创建一个文件test.js
包含this content和运行node --trace_gc test.js
或运行它通过Webstorm进行高级分析。
在 Javascript 和 v8(节点)中,特别是垃圾收集所花费的时间取决于堆中存储的数据量,但这只是众多因素之一。
在 v8 引擎中有两个主要的 "types" GC:minor (scavenge) 和 major (mark-sweep/mark-compact)。您可能会在启用 --trace-gc
的控制台中看到测试期间发生的 GC 类型。在不同的情况下,一种类型可能比另一种类型 "eat" 更多时间,反之亦然。所以在优化之前你应该确定哪个gc需要更多的时间。
没有太多优化主要 GC 的选项,导致它受保留在内存中 "long"(实际上在这种情况下很长意味着对象在清除 GC 中幸存)期间的数据量的影响很大。此类数据存储在堆中所谓的 "old space" 中。主要 GC 使用此 space,它应该扫描所有内存并标记不再有任何引用的对象以供进一步清除。
在您的情况下,您正在加载的测试数据量变为旧 space。因此,它会影响整个测试期间的主要 GC。在这种情况下,主要 GC 不会清除太多,因为你正在使用你的测试对象,但它仍然会消耗时间来扫描整个旧 space。因此,您可以考虑通过启动带有 gc 特定标志的节点来防止 v8 执行此操作,例如:--nouse-idle-notification --expose-gc --gc_interval=100500
(其中 100500 是分配数量,它可以采用高值来防止 运行 gc 在整个测试将通过),这将允许手动触发垃圾收集。使用这种方法测试你的代码,看看主要的 GC 是如何影响它的,尝试使用你提供的不同数据量进行测试。如果影响不大,您可以尝试重构您的代码,尽量减少长期变量、闭包等。
如果你会发现major GC对性能影响不大,那么scavenge GC占用的时间最多。与主要 GC 不同,它在堆中使用所谓的 "new space" 进行操作。这是一个 space 存储所有新对象的地方。如果这些对象在清除后幸存下来,那么它们将被移动到旧 space。新 space 的大小(您可以通过设置 --max_semi_space_size
来控制它,注意:new space size = 2 * semi space size
)比旧的 space 和更多的新对象和变量分配更多的清除 GC 运行会发生。如果此 GC 过度加热性能,您可以考虑重构您的代码以减少新分配。但是,如果您将重用变量,它也可能会降低性能,并且这些对象将变旧 space 并可能成为 "major GC" 部分中描述的问题。
此外,v8 GC 并不总是在您的程序运行的同一线程中工作。它也在后台做一些工作,但我不知道 Webstorm 在你的案例中显示了什么。如果它只计算在 GC 上花费的总时间,可能只是没有那么大的影响。 您可以在 blog post.
中找到有关 v8 GC 的更多详细信息长话短说:
Can the GC overhead be reduced?
- 是的,但首先您应该按照上述步骤发现应该优化的内容。
Is this amount of allocation just expected here?
- 这可以通过比较不同的方法来发现。没有绝对数字可以限制 "bad" 的 "good" 数量,因为它取决于很多因素,包括输入数据的数量。
Is it possible to get better memory profiling information?