使用子进程方式避免sharp rss占用过大
前些日子写了一篇文章-记一次内存泄漏处理,曲折过后发现并不是内存泄漏问题,而是rss占用过大,这篇文章讲述自己解决这个rss占用过大问题的一种方式:子进程调用。
前情回顾
应用中有一个服务端合成海报图片的功能,这个功能借助第三方库sharp实现,在应用运行一段时间后发现内存占用在500M以上,最初当成内存泄漏定位并在mac下重现了内存泄漏现象,但剧情反转,同样的代码在linux下并没有出现内存泄漏现象,随后经过一系列验证发现的确是rss占用过大的问题,最起码在linux下是。
详细内容可以参考记一次内存泄漏处理这篇文章,或者这个issue。
tips
rss是resident set size的缩写,即实际使用物理内存,rss占用过大与内存泄漏的区别在于前者是内存需求后者则是BUG,如果机器内存不够两者都会导致OOM(Out Of Memory)异常最终系统崩溃
子进程
进程是操作系统进行资源分配和调度的基本单位,从一个运行中的进程(父进程)中创建一个新的进程,这个新的进程就称为子进程,在Node.js中创建子进程主要依靠child_process
模块,但这个模块提供了多种创建的方式,相互之间也有一些差异,下面做一些简单的说明和对比。
child_process.spawn
spawn(command[, args][, options])
执行command命令,args是命令行参数数组,options则是关于子进程行为控制的选项,常用而且重要的有detached与stdio。
detached
分离,意思是子进程是否从父进程中分离出来,分离出来的子进程在父进程退出后仍可运行,未分离的子进程则受到linux下进程组等概念约束会随主进程一起退出。
曾经在做一个测试环境根据git webhook通过子进程方式自动部署功能时踩过这个坑,由于没有设置detached为true,当子进程通过pm2 reload xxx
时有概率先重启自己的父进程导致自己被杀掉了,从而导致其他进程没有重启。
stdio
stdio是standard input output的简称,标准输入输出,此处主要指如何处理子进程的stdin、stdout与stderr,主要有三种方式:
- pipe
pipe可以为子进程创建管道,灵活的处理子进程输入输出相关逻辑,这是默认行为
- ignore
ignore会忽视子进程的输入输出,类似在shell中执行命令没有输入并把输出重定向到/dev/null
- inherit
inherit是共享父进程的标准输入输出,如父进程的
console.log
是输出在屏幕上,则子进程中的输出同样会打印在屏幕上
child_process.exec
exec(command[, options][, callback])
在shell中执行command命令,callback函数会返回err、stdout与stderr,options与spawn类似也有不同。
首先是command的区别,在spawn中命令行参数通过args数组传递,在exec中则是与command拼接在一起,拿列出/root
目录下的文件举例:
const cp = require('child_process'