在Node.js中处理大文件和节点以及内存限制

问题描述

我必须打开一个非常大的文件〜15GB,并尝试使用fs.readFileSync读取整个文件,然后根据一个密钥将整个文件放入哈希映射中以对文件进行去重复。但是很快我遇到了一个问题,由于v8限制,我无法将整个文件读入内存!

我尝试使用-max-old-space-size传递更大的内存,但仍然无法正常工作。

那是为什么?

这是nodejs的限制还是我缺少了什么?

我的机器上有64GB RAM。

例如,有一个具有以下格式的大文件data.txt,我必须基于uuid进行重复操作:

new record
field_separator
1fd265da-e5a6-11ea-adc1-0242ac120002 <----uuid
field_separator
Bob
field_separator
32
field_separator
Software Engineer
field_separator
Workday
point_separator
new record
field_separator
5396553e-e5a6-11ea-adc1-0242ac120002
field_separator
Tom
field_separator
27
this is a field3
QA Engineer
field_separator
Synopsis
point_separator
........

还有另一个小文件(200兆),其中包含具有不同值的UUID。我必须使用上述文件中的UUID进行查找。

脚本只是一次处理。

解决方法

Node documentation指出,最大缓冲区大小在32位系统上约为1GB,在64位系统上约为2GB。

您还可以在Stack Overflow上搜索有关V8(Node.js中使用的JavaScript引擎)使用的objectsheap memory的最大大小的问题。

我认为将15GB文件读入内存并根据其全部内容创建对象的机会约为零,并且您将需要寻找fs.readFileSync的替代方案(例如读取流,使用数据基本服务器或使用其他服务器)。

可能值得验证堆统计信息中的“可用”内存值是否反映了使用CLI选项--max-old-space-size设置的大小。 Heap statistics可以通过运行生成

const v8 = require("v8");
console.log( v8.getHeapSpaceStatistics());
console.log( v8.getHeapStatistics());

在节点中。

A question answered in 2017问有关增加字符串大小的固定限制的问题。此后可能会增加,但Comment 9 in (closed) issue 6148表示它不可能超过32位寻址(4GB)的限制。

在不更改缓冲区和字符串大小限制的情况下,fs.readFileSync无法读取和返回16GB文件的内容作为字符串或缓冲区。

,

如果您要执行的操作是这样:

将记录追加到UUID唯一的较小文件(较小文件中尚不存在)

然后,我建议执行以下过程。

  1. 设计一种方案,用于从文件中读取下一条记录并将数据解析为Javascript对象。
  2. 使用该方案可读取较小文件中的所有记录(一次读取一条记录),并将该文件中的每个UUID添加到$date = Carbon::parse($timeStamp)->format('M d Y'); 对象中(以保持唯一性)。
  3. 在处理完小文件之后,现在有了一个Set对象,其中包含所有已知的UUID。
  4. 现在,使用相同的读取方案从较大的文件读取每个下一个记录(一次一个记录)。如果记录不在UUID集中,则将其添加到该集中并将该记录附加到较小的文件中。如果记录在UUID集中,请跳过它。
  5. 继续从大文件中读取记录,直到您全部选中为止。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...