Nodejs内存控制详解(上篇)
1 V8的垃圾回收机制与内存限制
JavaScript与Java一样,由垃圾回收机制来进行自动的内存管理。对于性能敏感的服务器端程序,内存管理的好坏、垃圾回收状况是否优良,都会对服务构成影响。而在Node中,这一切与V8引擎息息相关。
1.2 V8的内存限制
Node中通过JavaScript只能使用部分内存(64位约1.4G,32位约0.7G)。V8对内存做了限制。因此这种限制下,将会导致Node无法直接操作大内存对象。
1.3 V8的对象分配
V8中,所有的JavaScript对象都是通过堆来分配的。
可以使用以下命令查看Node中V8内存的使用量。
> $ node > process.memoryUsage(); { rss: 25939968, heapTotal: 5767168,//已申请到的堆内存 heapUsed: 4707312,//当前使用的量 external: 8671 }
至于rss为何物,我们会在下面介绍。
V8的堆示意图:
限制内存原因:
- 首先V8是为浏览器而设计的;前期足以满足网页端的需求;
- 深层原因是V8的垃圾回收机制,垃圾回收耗时,引起JavaScript线程暂停执行时间。
- 可以手工调整内存大小
node --max-old-space-size=1700 test.js //单位为MB。设置老生代 node --max-new-space-size=1024 test.js //单位为KB。设置新生代
1.4 V8的垃圾回收机制
主要的垃圾回收策略是
基于分代式
的垃圾回收机制:将对象的存活时间进行不同的分代
;
V8中,主要将内存分为新生代和老生代。新生代中的对象为存活时间较短的对象,老生代中的对象为存活时间较长或常驻内存的对象。
-
前面讲到的命令是可以分别设置新生代和老生代的大小。
-
新生代和老生代的最大值需要在启动时就指定,因此无法动态 扩展。手工设置新生代或老生代的内存,只能在启动时就指定,无法动态的扩展。
Scavenge算法
在分代的基础上,新生代中的对象主要通过Scavenge算法进行垃圾回收。Scavenge算法的具体实现中采用了Cheney算法。
- Cheney算法主要使用了
复制
的方式实现。
- 新生代堆内存被一分为二
- From区存放处于使用状态对象
- TO区为闲置空间
- 分配对象时首先在From分配
- 垃圾回收时,检查From空间中的存活对象,将这些对象复制到TO空间。非存活对象直接释放对应空间。
- 垃圾回收实际上就是将对象在
FROM
和TO
两个空间之间复制。 - 多次复制仍然存活的对象,即生命周期较长的对象,会被移动到老生代。
- 对象从新生代到老生代的过程称为
晋升
- 对象晋升过程:
另一个判断条件是:TO空间使用是否超过25%。如果超过,直接移动到老生代。
设置25%这个值,是因为当Scavenge完成回收后,这个TO区将变成From区,后面的对象分配要在这个区中进行。如果占比过高,会影响后续的内存分配。
Scavenge的缺点是只能使用堆内存的一半。所以无法大规模的运用到所有的垃圾回收中。但是时间效率上有优异的表现。因此非常适合新生代的垃圾回收,因为新生代中的对象存活周期都较短。
Mark-Sweep & Mark-Compact算法
老生代中主要采用这两种算法进行垃圾回收。
因为老生代中的存活对象占比较大,因此使用Scavenge算法会有弊端:
- 存活对象多,复制效率低;
- 浪费一半空间;
1.Mark-Sweep:标记清除
分为标记、清除两个阶段;
- 标记阶段会遍历堆中的所有对象,并只标记活着的对象;
- 清除阶段只清除没有被标记的对象;
Mark-Sweep | Scavenge
--- | ---
只清理死亡对象 | 只复制存活对象
死对象在老生代中比重小 | 活对象在新生代中比重小
Mark-Sweep的最大问题即是:在清理完后,内存会出现不连续的状态。导致后续对内存的分配可能出现问题,如无法分配一个大对象。
2.Mark-Compact:标记整理
为了解决Mark-Sweep的问题。Mark-Compact在标记对象死亡后,在整理过程中,将活着的对象往一端移动,移动完成后,直接清理掉边界外的内存。
算法比较
| 算法 | Mark-Sweep | Mark-Compact | Scavenge
---| --- | -- |--
速度 | 中等| 最慢 | 最快
空间开销 | 少(有碎片)|少(无碎片)| 双倍空间(无碎片)
是否移动对象 | 否 | 是 | 是
V8主要使用Mark-Compact,在空间不足以对从新生代中晋升过来的对象进行分配时才使用Mark-Sweep。
原文发布时间为:2018年01月20日
原文作者:sunangie
本文来源:开源中国 如需转载请联系原作者
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
2017年 JavaScript 框架回顾 -- React生态系统
前一篇文章中,我们介绍了2017年 JavaScript 框架的整体情况。我们也了解到在众多的前端框架中,目前最为庞大又在快速增长的当属 React 了,本文就来重点介绍 React 的生态系统。 首先看看与 React 有关的软件包的生态系统。在 Facebook 构建 React 之初,就有许多来自于开源社区第三方库的软件包。这些软件包使用 React 补充其它功能,以便提供完整的应用程序解决方案。当然,安装包中也存在着提供相似功能的彼此竞争关系。 React Router 丰富的 Web 应用程序具有的一个共同特点就是:提供了多个“路由”。这些“路由”本质上是不同的功能块,在浏览器中表现为单独的 URL。React 不需要为简单的应用程序使用路由,同时在一些桌面和移动应用程序环境中,路由也不是必需的。因此,React Router 虽然是最受欢迎的 React 应用程序的路由解决方案,但 React Router 的相对流行程度却只有 React 的一半。 了解 React 的开发者都知道,React 应用于一个明确定义的问题领域并具有明确定义的接口,这也使其本身可以应用于比原...
- 下一篇
剥开比原看代码05:如何从比原节点拿到区块数据?
作者:freewind 比原项目仓库: Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockchain/bytom 在前一篇中,我们已经知道如何连上一个比原节点的p2p端口,并与对方完成身份验证。此时,双方结点已经建立起来了信任,并且连接也不会断开,下一步,两者就可以继续交换数据了。 那么,我首先想到的就是,如何才能让对方把它已有的区块数据全都发给我呢? 这其实可以分为三个问题: 我需要发给它什么样的数据? 它在内部由是如何应答的呢? 我拿到数据之后,应该怎么处理? 由于这一块的逻辑还是比较复杂的,所以在本篇我们先回答第一个问题: 我们要发送什么样的数据请求,才能让比原节点把它持有的区块数据发给我? 找到发送请求的代码 首先我们先要在代码中定位到,比原到底是在什么时候来向对方节点发送请求的。 在前一篇讲的是如何建立连接并验证身份,那么发出数据请求的操作,一定在上次的代码之后。按照这个思路,我们在SyncManager类中Switch启动之后,找到了一个叫BlockKeeper的类,相关的...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- CentOS7设置SWAP分区,小内存服务器的救世主
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- SpringBoot2整合Redis,开启缓存,提高访问速度
- SpringBoot2整合Thymeleaf,官方推荐html解决方案