【问题标题】:How to increase EsLint memory to avoid `JavaScript heap out of memory`?如何增加 EsLint 内存以避免`JavaScript heap out of memory`?
【发布时间】:2019-06-23 18:19:42
【问题描述】:

我正在尝试在 非常 大的 javascript 文件上运行 EsLint,但进程内存不足。为了让您了解文件有多大,我在上面运行了Cloc,这是输出:

$ cloc app.js 
       1 text file.
       1 unique file.                              
       0 files ignored.

github.com/AlDanial/cloc v 1.80  T=12.81 s (0.1 files/s, 42499.8 lines/s)
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
JavaScript                       1           4255          23744         516524
-------------------------------------------------------------------------------

文件大小为 23MB。

$ ls -lAh app.js 
-rw-r--r-- 1 miguelangel staff 23M Jan 28 11:58 app.js

这就是说这很可能不是 EsLint 中的内存泄漏。我在 Github.com 中看到 EsLint 存在内存泄漏的一些问题。我认为情况并非如此。

文件这么大是因为它是连接许多其他 Javascript 模块的结果。我的目标是尝试找到任何未使用的代码。这个项目的代码库显然在不受控制的情况下增长,我正试图摆脱自重。所以我试图在整个代码库的串联上运行EsLint's no-unused-vars rule。这是我的 EsLint 配置文件:

.eslintrc.js

module.exports = {
    "env": {
        "browser": true,
        "commonjs": false,
        "es6": true
    },
    "parserOptions": {
        "ecmaVersion": 2015
    },
    "rules": {
        "no-unused-vars": [
            "warn"
        ]
    }
};

这个项目既不是 Node 也不是 AMD 项目,所以我认为我必须将整个代码库放在一个文件中以避免误报。

问题是尝试在此文件上运行 EsLint 会导致 JavaScript heap out of memory 错误。

$ eslint app.js 

<--- Last few GCs --->

[60451:0x104002200]    43814 ms: Mark-sweep 1395.7 (1424.1) -> 1395.2 (1423.6) MB, 5719.6 / 0.0 ms  (+ 0.1 ms in 28 steps since start of marking, biggest step 0.0 ms, walltime since start of marking 5755 ms) (average mu = 0.148, current mu = 0.037) alloca[60451:0x104002200]    49447 ms: Mark-sweep 1397.4 (1424.1) -> 1396.9 (1425.6) MB, 5569.8 / 0.0 ms  (+ 0.1 ms in 11 steps since start of marking, biggest step 0.0 ms, walltime since start of marking 5598 ms) (average mu = 0.081, current mu = 0.011) alloca

<--- JS stacktrace --->

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

    0: ExitFrame [pc: 0x3275f3d4fb7d]
Security context: 0x14c691f9d969 <JSObject>
    1: /* anonymous */ [0x14c6f1b7b981] [/usr/local/lib/node_modules/eslint/node_modules/acorn/dist/acorn.js:~2868] [pc=0x3275f40f5843](this=0x14c6b794c669 <Parser map = 0x14c603088f11>)
    2: /* anonymous */ [0x14c6f1b7b111] [/usr/local/lib/node_modules/eslint/node_modules/acorn/dist/acorn.js:2190] [bytecode=0x14c691fecb01 offset=968](this=0x14c6b794c669 <...

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
 1: 0x10003ace0 node::Abort() [/usr/local/bin/node]
 2: 0x10003aeb1 node::OnFatalError(char const*, char const*) [/usr/local/bin/node]
 3: 0x10018c8cf v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [/usr/local/bin/node]
 4: 0x10018c870 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/usr/local/bin/node]
 5: 0x10047b188 v8::internal::Heap::UpdateSurvivalStatistics(int) [/usr/local/bin/node]
 6: 0x10047cc01 v8::internal::Heap::CheckIneffectiveMarkCompact(unsigned long, double) [/usr/local/bin/node]
 7: 0x10047a4c4 v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags) [/usr/local/bin/node]
 8: 0x100479236 v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/usr/local/bin/node]
 9: 0x100481826 v8::internal::Heap::AllocateRawWithLightRetry(int, v8::internal::AllocationSpace, v8::internal::AllocationAlignment) [/usr/local/bin/node]
10: 0x100481b5c v8::internal::Heap::AllocateRawWithRetryOrFail(int, v8::internal::AllocationSpace, v8::internal::AllocationAlignment) [/usr/local/bin/node]
11: 0x100461562 v8::internal::Factory::NewFillerObject(int, bool, v8::internal::AllocationSpace) [/usr/local/bin/node]
12: 0x100653464 v8::internal::Runtime_AllocateInNewSpace(int, v8::internal::Object**, v8::internal::Isolate*) [/usr/local/bin/node]
13: 0x3275f3d4fb7d 
Abort trap: 6

如何增加 EsLint 对内存的访问?

【问题讨论】:

  • Google 的Closure Compiler 可能更适合您的情况。您可以添加声明,有点像 C/C++ 中的 #include,请参阅 @externs。这样你仍然可以运行 100% 正确的定义。我只将它用作 linter,它非常擅长发现即使 eslint 也找不到的问题。而且你可以分解模块或项目中的代码,仍然可以得到完全类型化的检查。
  • @AlexisWilke 您能否展示或指出一个示例,说明如何使用闭包编译器标记未使用的代码而不删除它?我不只是希望将其从最终发行版中删除。我想清理代码库。
  • 我认为您可以使用--jscomp_error=uselessCode 命令行选项,这样您就可以得到任何未明确调用的函数的错误。
  • uselessCode 警告似乎是您正在寻找的警告。就我而言,我不使用 Closure 编译器的输出。相反,我使用它或多或少像一个静态分析器,它告诉我诸如“你用字符串而不是数组调用这个函数”,我认为这非常有用。

标签: javascript eslint heap-memory


【解决方案1】:

默认情况下,Node.js 将内存限制设置为接近 1.5 GB。您可以通过 --max_old_space_size 键增加它(例如,--max_old_space_size=4096 以使用 4 GB)。

要使用密钥,您需要知道 ESLint 主文件的路径并以这种方式将其作为脚本调用:

node --max_old_space_size=4096 ./node_modules/eslint/bin/eslint.js app.js

【讨论】:

  • 这是一个很好的解决方法,但我希望能做一些不那么冗长的事情,并且可以只做一次。
  • 将它添加到你的 package.json 的脚本中,然后在你想要 lint 时运行 npn run lint
  • 试试这个,以防 eslint 移动他们的文件位置node --max_old_space_size=4096 ./node_modules/.bin/eslint app.js
【解决方案2】:

我浏览了 EsLint 文档,希望找到一个选项来配置它以使用更多内存运行。很遗憾,我找不到任何类似的东西。

但是,受到@vsemozhetbyt 的回答的启发——因此获得了赞成票——我开始查看 Node 的配置选项,并找到了使用Node's NODE_OPTIONS environment variable 解决此问题的方法。

以空格分隔的命令行选项列表。选项...被解释为在实际命令行之前的命令行中指定了它们

这就是我所做的:

$ export NODE_OPTIONS="--max-old-space-size=4096"
$ echo $NODE_OPTIONS
--max-old-space-size=4096
$ eslint app.js

这样,运行 EsLint 的 Node 进程只需在每次调用 EsLint 时都无需我输入 --max-old-space-size 标志或 Node 二进制文件的路径即可获取它。

【讨论】:

    【解决方案3】:

    如果所有关于增加节点--max_old_space_size 的答案都无济于事,那么值得从不同的角度来看看它。 可能错误太多,Node heap 真的内存不足。

    我遇到过这种情况:

    我加入了有很多 .js/.vue 文件的大项目。在.eslintrc"linebreak-style": [2, "unix"] 中,这意味着行尾字符应该是lf。我使用Windows,其中eol 字符是crlf。 Git 默认将所有内容转换为crlf。所以当我从 git 克隆这个项目时,我看到了很多来自 Eslint 的关于 Visual Studio Code 中错误 eol 字符的警告,但来自控制台的eslint 总是以heap out of memory 结尾。

    对于上述情况,关于node out of memory 的任何建议都没有帮助导致问题出现在其他地方。

    【讨论】:

    • 谢谢!有 1000 多个错误,最终在我将 typescript 升级到 v3.9.3 时显示出来。它有更好的构建时间,因此 eslint 也从中受益。解决错误时,必须再次降级 typescript 以使其与 Angular 编译器一起使用。但是问题解决了!
    【解决方案4】:

    我在 Laravel/Vue 应用程序中遇到了这个问题。这些细节并不重要,但事实上 Laravel 有一些文件夹,例如 vendor,其中包含所有 composer 包,这意味着 ES Lint 正在遍历大量文件,足以炸毁堆。

    解决方法是先在项目根目录下添加一个.eslintignore文件,如:

    /app
    /bootstrap
    /config
    /database
    /node_modules
    /public
    /routes
    /storage
    /tests
    /vendor
    

    接下来,从 CLI(和 GitLab-CI)执行 ES Lint:

    node_modules/eslint/bin/eslint.js --config ./.eslintrc.json .
    

    确保 ES Lint 使用正确的配置文件来检查预期的规则集也很重要。

    您可以通过在 CLI 命令中添加 --debug 来直观地测试其中的一些内容,如果发生这种情况,您将看到它遍历非法文件夹和文件。我认为这是一个不错的调试步骤——以详细模式对其进行测试。您可能会看到 ES Lint 遍历不必要的文件夹或针对不正确的规则进行测试。

    在我看来,这个问题很容易源于 ES Lint 在工作时试图将大量错误加载到内存中。无需增加堆,您可以拨入 ES Lint 的 lint 究竟是什么。

    【讨论】:

    • 我的项目有一个 eslintignore 文件,但最近的更改创建了一个新文件夹,其中包含构建文件。此新文件夹未添加到忽略列表中,因此导致了问题。谢谢提醒!
    • 我认为实际上应该先探索这个解决方案,然后再尝试增加 Node.js 的可用内存。我这样说是因为我只是在我的项目中添加了一个 .eslintignore,忽略了 node_modules 和其他一些文件夹,并且 ESLint 停止了内存不足。
    • 我同意,因为如果你把场景想象成一杯可以装满的水,增加玻璃杯的高度确实可以解决这个问题,但它并没有解决原来的问题,即为什么水是一开始就这么高。重要的是要确保您的项目了解要 lint 和避免 lint 的内容。
    【解决方案5】:

    从 TSLint 迁移到 ESLint 后,我​​遇到了同样的错误。就我而言,打字稿配置是一个瓶颈。 tslint.json 文件中的这一行:

    "extends": "tslint-consistent-codestyle"
    

    通过此扩展,每个文件都被分析了十几秒(2-3 分钟后出现内存不足错误)。没有它,所有项目(数百个文件)都会在几秒钟内完成分析。

    【讨论】:

      猜你喜欢
      • 2012-03-09
      • 2017-04-24
      • 2019-06-18
      • 2018-08-01
      • 1970-01-01
      • 2021-09-02
      • 1970-01-01
      • 1970-01-01
      • 2017-05-21
      相关资源
      最近更新 更多