nodejs 使用 express 传输大文件(140M 左右)时崩溃(出现 GC 异常)

环境说明

嵌入式设备,搭建的是 ubuntu 系统
nodejs 版本 v12.18.0

问题遇到的现象和发生背景

在我的一个嵌入式设备中,需要使用 nodejs + express 传输文件,文件大小为 140M 左右,结果导致 nodejs 崩溃,打印异常信息如下

<--- Last few GCs --->

[1767:0x1fb9640]    50630 ms: Mark-sweep 284.2 (289.3) -> 284.1 (285.8) MB, 119.6 / 0.0 ms  (average mu = 0.944, current mu = 0.003) last resort GC in old space requested
[1767:0x1fb9640]    50700 ms: Mark-sweep 284.1 (285.8) -> 284.1 (285.8) MB, 69.7 / 0.0 ms  (average mu = 0.910, current mu = 0.001) last resort GC in old space requested


<--- JS stacktrace --->

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

Security context: 0x42da58b9 <JSObject>
    0: builtin exit frame: byteLength(aka byteLengthUtf8)(this=0x3f764a79 <Object map = 0x2ecd615d>,0x3ae30491 <Very long string[147123807]>,0x3f764a79 <Object map = 0x2ecd615d>)

    1: fromStringFast(aka fromStringFast) [0x3f7630b1] [buffer.js:424] [bytecode=0x3f77fe35 offset=7](this=0x495c0279 <undefined>,0x3ae30491 <Very long string[147123807]>,0x3f764a79 <Object map = 0x2ecd615d>)
    2: fromSt...

相关代码简化之后如下

let getSystemLog = function(req, res) {
  let content = '';

  if (fs.existsSync(system_log_file1)) {
    content += "\n>>>>>>>>>>" + system_log_file1 + "<<<<<<<<<<\n" + fs.readFileSync(system_log_file1);
  }

  if (fs.existsSync(system_log_file2)) {
    content += "\n>>>>>>>>>>" + system_log_file2 + "<<<<<<<<<<\n" + fs.readFileSync(system_log_file2);
  }

  res.send(content);
};

针对这个问题,自己查过一些资料,了解 nodejs 的大致 GC 机制,以及 nodejs v8 的堆栈限制。初步怀疑是 nodejs 堆栈限制导致的问题

我的解答思路和尝试过的方法

我有尝试过压缩之后再传输,然而由于嵌入式资源有限,压缩时间太长(需要十多分钟),所以这种方法并不实用

我想要达到的结果

所以能否有朋友帮忙解答如下问题:
1、怎么查看和设置当前 nodejs 的堆栈大小
2、对于大文件传输,有没有其他更高效的方式

不胜感激

这个为什么不考虑streaming方式传输呢

估计你把res.send换成res.write(就是要用buffer之类的分块) 最后加一个res.end 就没事了,在接收那里也处理streaming chunks 就可以了但是不处理通常也会自动处理的

function(req, res, next) {
  if(req.url==="somethingorAnother") {
    res.setHeader("content-type", "some/type");
    fs.createReadStream("./toSomeFile").pipe(res);
  } else {
    next(); // not our concern, pass along to next middleware function
  }
}

这样也可以。

看看https://www.jb51.net/article/157806.htm
https://www.jb51.net/article/157806.htm
https://www.csdn.net/tags/MtzaQg3sNjMwNjYtYmxvZwO0O0OO0O0O.html

140M文件整个读到内存再发送?哪有你这么用的?
任何开发语言,正常做法都是,读一段数据发一段数据
nodejs中的可读流有个pipe方法相当于封装好的,可以直接使用
代码改改吧,
let file = fs.createReadStream...
file.pipe(res)

需要采用文件分片的方式来传输,你传送文件走的是HTTP协议,不卡死才怪。
你可以前后端协商,可以将文件分成200片,或者1000片,累计记录每次分片的序号,然后后端现将这些分片文件接收后,再将这些文件合并为一个文件就可以了。这个之前做过,还是很清楚的