要点记录:
1、网页js、命令行工具,快进快出的,即时内存泄露,无内存管理必要!
2、服务器端nodejs和其他正规语言一样存在内存泄露。
3、nodejs基于谷歌v8js引擎,速度很快,垃圾回收也是由v8维护的
4、通过查看源码可发现v8中用js使用内存的限制约为:64位-1.4G 32位 -0.7G。这是源于v8的垃圾回收机制的限制,可在node 后加 --max-old|new-space-size=xxx来改变内存限制
5、nodejs进程的内存占用:堆内内存+堆外内存=rss+swap+fs,
其中v8申请和分配的为堆内内存,所有js实体都是通过堆来分配的。process.memoryUsage() 可查看常驻内存rss,heapTotal总堆内存,和已分配的堆内存heapUsed
非V8分配的内存为堆外内存,如 Buffer对象占据的内存,用在网络流和文件流中
os.totalmem os.freemem 可查看系统的总内存和可用 内存
6、v8的垃圾回收算法
统计学知识的应用,按对象存活时间将内存的垃圾回收进行不同的分代,对这些不同的分代分别实施不同的回收算法
v8中将内存主分为新生代 和 老生代 空间,前者存活时间短,后者较长或常驻
7、新生代中活对象较少,采用scavenge-cheney算法:将新生代一分为二,From ->To ,新对象分配在from中,回收时将From中活的对象从From复制到To,释放From,然后From和To互换角色。
8、一个对象从From复制到To时,如果ta之前经历过一次scavenge复制,或者to空间已经使用了25%了,则该对象会直接晋升到老生代空间中,接受其他回收算法
9、老生代活对象较多,采用mark-sweep和mark-compact相结合的方法:m-s,不再划分内存空间,标记阶段标记所有活的对象,清理阶段清除释放所有未标记(死了的)对象,这一步会产生内存空间碎片,因此出现了m-c,边标记边将活动的对象往内存空间的一端 移动,清理时直接清理活死对象边界死的那端。移动对象是耗时的,所以主要使用 m-s算法,当不足以分配空间给从新生代晋升来的对象时,才使用m-c回收。
10、全停顿---每次垃圾回收时都会暂停应用逻辑,是为了避免应用逻辑和回收器看到的对象不一致。
11、增量动作,v8的分代垃圾回收中,分为full和part方式,part只回收新生代的,因为新生代空间小啊,全停顿影响不大,但是full回收会回收老生代的,全停顿的时间就不能接受了,于是就有了 增量式标记incremental marking。即将标记工作分步,每步和应用逻辑交替执行,这样最大停顿时间减少很多,(六分之一);
其他阶段就有:延迟清理,增量式整理compact,利用多核来并行标记和清理
12、查看垃圾回收动作日志:启动node时 加 --trace_gc 参数, --prof参数可得到v8执行性能参数,用*-tick-processor查看
13、无法立即回收的内存有全局变量和闭包,尽量使用变量赋值为null|undefined来触发回收
14、内存泄露:该回收的对象出现意外没有被回收,来自于:缓存,队列消费不及时,作用域未释放
15、慎用内存当缓存,非用的话控制好缓存的大小和过期时间,方式出现永远无法释放的问题,采用redis,memX
16、数组、回调,生产者的速度比消费者速度快,堆积了大量生产者导致无法释放作用域或变量: 队列监控,异步调用应包含超时处理机制
17、内存泄露排查,网上搜索node应用内存查看分析工具
node-headdump
node-memwatch
18、大文件处理使用stream模块
来源:oschina
链接:https://my.oschina.net/u/26712/blog/270248