问题描述
我必须打开一个非常大的文件〜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引擎)使用的objects或heap 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唯一的较小文件(较小文件中尚不存在)
然后,我建议执行以下过程。
- 设计一种方案,用于从文件中读取下一条记录并将数据解析为Javascript对象。
- 使用该方案可读取较小文件中的所有记录(一次读取一条记录),并将该文件中的每个UUID添加到
$date = Carbon::parse($timeStamp)->format('M d Y');
对象中(以保持唯一性)。 - 在处理完小文件之后,现在有了一个
Set
对象,其中包含所有已知的UUID。 - 现在,使用相同的读取方案从较大的文件读取每个下一个记录(一次一个记录)。如果记录不在UUID集中,则将其添加到该集中并将该记录附加到较小的文件中。如果记录在UUID集中,请跳过它。
- 继续从大文件中读取记录,直到您全部选中为止。