Node.js似乎在循环后没有释放内存

问题描述 投票:1回答:1
const axios = require('axios');
const JSDOM = require('jsdom').JSDOM;

axios.get('https://facebook.com')
    .then(response => {
        let i=1;
        while (true) {
            console.log(i++);
            const dom = new JSDOM(response.data);
            dom.window.close();
        }
    });

以上代码将在我的计算机上运行440次,然后崩溃,并显示以下内容:

<--- Last few GCs --->

[13411:0x5dc70d0]    63566 ms: Mark-sweep 2042.3 (2051.1) -> 2041.3 (2051.1) MB, 2407.4 / 0.0 ms  (average mu = 0.123, current mu = 0.027) allocation failure scavenge might not succeed
[13411:0x5dc70d0]    67327 ms: Mark-sweep 2042.0 (2051.1) -> 2041.1 (2050.9) MB, 3745.2 / 0.0 ms  (average mu = 0.055, current mu = 0.004) allocation failure scavenge might not succeed


<--- JS stacktrace --->

==== JS stack trace =========================================

    0: ExitFrame [pc: 0x145cc79]
    1: StubFrame [pc: 0x145dab5]
Security context: 0x0d2e98240921 <JSObject>
    2: /* anonymous */ [0x374dcc798739] [/pathtomyproject/node_modules/parse5/lib/tokenizer/index.js:~644] [pc=0x323d7cd98d24](this=0x10b528b73279 <Tokenizer map = 0x242f38ec5c11>,95)
    3: getNextToken [0x374dcc799419] [/pathtomyproject/node_modules/parse5/lib/tokenizer/i...

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory

Writing Node.js report to file: report.20200215.163602.13411.0.001.json
Node.js report completed
 1: 0xa9d570 node::Abort() [node]
 2: 0xa9f832 node::OnFatalError(char const*, char const*) [node]
 3: 0xc0758e v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [node]
 4: 0xc07909 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [node]
 5: 0xdb5e15  [node]
 6: 0xdb64a6 v8::internal::Heap::RecomputeLimits(v8::internal::GarbageCollector) [node]
 7: 0xdc4d19 v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags) [node]
 8: 0xdc5b55 v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [node]
 9: 0xdc862c v8::internal::Heap::AllocateRawWithRetryOrFailSlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [node]
10: 0xd8f204 v8::internal::Factory::NewFillerObject(int, bool, v8::internal::AllocationType, v8::internal::AllocationOrigin) [node]
11: 0x10dc52e v8::internal::Runtime_AllocateInYoungGeneration(int, unsigned long*, v8::internal::Isolate*) [node]
12: 0x145cc79  [node]
Aborted (core dumped)

所以我想即使在每次迭代中重新分配了dom之后,先前的值仍将存储在堆中。为什么会这样,如何预防呢?

javascript node.js memory axios jsdom
1个回答
0
投票
V8中的垃圾回收是在您的代码未运行并且在执行这些操作之间完成的。您的while(true)循环会永远运行,因此您永远不会更改V8进行垃圾回收。

由于许多其他原因,您永远不会在Javascript中进行永久运行的循环(除非循环中没有await),因为nodejs是一个主要是单线程事件驱动的系统,并且在您忙于在[ C0]循环,无法处理任何事件,因此在nodejs中无法完成很多事情。

为什么会这样,如何防止呢?

垃圾回收器通常被设计为让您的代码运行并且不干扰其执行,然后,在您的代码不执行任何操作并且已完成其内部状态的瞬间,垃圾回收器将检查堆中对象的状态,以查找不再使用的对象。

您可以在不提供GC可以运行的任何空闲时间的情况下,避免陷入这种紧密循环,从而避免出现这种情况。如上所述,像这样的紧密循环会阻止nodejs中的任何其他事件继续运行,因此,出于其他原因,通常也是不好的原因。

注意,您的代码不仅创建了444个while(true)实例以及与这些实例相关联的所有对象,而且没有提供清除创建该[]时使用的所有临时变量/字符串的任何功能。 C0]实例,在解析HTML时可能是实质性的,因此总内存使用量明显高于仅444个完成的dom实例。如果您在循环中插入任何类型的呼吸室,则GC将有机会清理不再使用的东西。

© www.soinside.com 2019 - 2024. All rights reserved.