对象分配

所有的JS对象都是通过堆来进行分配的。使用process.memoryUsage()查看使用情况Node.js 中文网文档

process.memoryUsage()
{ rss: ,
heapTotal: ,
heapUsed: ,
external: }
// 单位 字节
// rss (resident set size) 常驻进程内存 所有内存占用
// heapTotal 已申请堆内存
// heapUsed 已使用堆内存
// external c++对象绑定到js的内存

内存限制

内存限制主要原因是v8的垃圾回收制度。1.5GB内存做一次小的回收需要50MS,做一次非增量性回收需要1S以上,并且这会使JS线程暂停。因此限制内存。

V8的堆组成

V8的堆由一系列区域组成:

新生代区:大多数对象的创建被分配在这里,这个区域很小,但垃圾回收非常频繁,独立于其它区。

老生代指针区:包含大部分可能含有指向其它对象指针的对象。大多数从新生代晋升(存活一段时间)的对象会被移动到这里。

老生代数据区:包含原始数据对象(没有指针指向其它对象)。Strings、boxed numbers以及双精度unboxed数组从新生代中晋升后被移到这里。

大对象区:这里存放大小超过其它区的大对象。每个对象都有自己mmap内存。大对象不会被回收。

代码区:代码对象(即包含被JIT处理后的指令对象)存放在此。唯一的有执行权限的区域(代码过大也可能存放在大对象区,此时它们也可被执行,但不代表大对象区都有执行权限)。

Cell区、属性Cell区以及map区:包含cell、属性cell以及map。每个区都存放他们指向的相同大小以及相同结构的对象。

v8在64位系统下只能使用1.4GB内存,在32位系统下只能使用0.7GB内存。

如何解除内存限制?

利用堆外内存: 使用Buffer类。Buffer 性能相关部分由C++实现。Buffer教程

在启动node时,传递--max-old-space-size=4096 (调整老生代内存限制,单位为mb。--max-new-space-size 已经不可用了)

使用stream处理大文件 stream教程

官方建议:it is recommended that you split your single process into several workers if you are hitting memory limits. (拆分进程)

垃圾回收机制

V8的垃圾回收有如下几个特点
当处理一个垃圾回收周期时,暂停所有程序的执行。(stop-the-world 全停顿)  

在大多数垃圾回收周期,每次仅处理部分堆中的对象,使暂停程序所带来的影响降至最低。(增量标记等算法) 

准确知道在内存中所有的对象及指针,避免错误地把对象当成指针所带来的内存泄露。(标记指针法:在每个指针的末位预留一位来标记这个字代表的是指针或数据。)

在V8中,对象堆被分为两个部分:新创建的对象所在的新生代,以及在一个垃圾回收周期后存活的对象被提升到的老生代。
如果一个对象在一个垃圾回收周期中被移动,那么V8将会更新所有指向此对象的指针。

内存泄漏

谷歌:什么是内存泄漏

百度:什么是内存泄漏

常见原因 1.缓存 2.队列消费不及时 3.作用域未释放

1 : 缓存

var cache = {};
function set (key, value){
cache[key] = value;
}

2 : 无限增长数组

var arr = [];
function x (value){
arr.push(value);
}

3: 无限重连导致的内存泄漏

const net = require('net');
let client = new net.Socket(); function connect() {
client.connect(26665, '127.0.0.1', function callbackListener() {
console.log('connected!');
});
} //第一次连接
connect(); client.on('error', function (error) {
// console.error(error.message);
}); client.on('close', function () {
//console.error('closed!');
//泄漏代码
client.destroy();
setTimeout(connect, 1);
});

泄漏产生的原因其实也很简单:event.js 核心模块实现的事件发布/订阅本质上是一个js对象结构(在v6版本中为了性能采用了new EventHandles(),并且把EventHandles的原型置为null来节省原型链查找的消耗),因此我们每一次调用 event.on 或者 event.once 相当于在这个对象结构中对应的 type 跟着的数组增加一个回调处理函数。

那么这个例子里面的泄漏属于非常隐蔽的一种:net 模块的重连每一次都会给 client 增加一个 connect事件 的侦听器,如果一直重连不上,侦听器会无限增加,从而导致泄漏。

4: 测试:

var run = function () {
var str = new Array(1000000).join('*');
var doSomethingWithStr = function () {
if (str === 'something')
console.log("str was something");
};
doSomethingWithStr();
};
setInterval(run, 1000);

最新文章

  1. ffmpeg编译常规大全
  2. java调用Linux命令报错:java.io.IOException: Cannot run program "ps": CreateProcess error=2, ?????????
  3. C#写Windows Service(windows服务程序)
  4. win10 用微软账户登录无法访问共享的问题
  5. Android自定义的webView——可实现的网页文本的复制
  6. git提交时的冲突处理
  7. 使用线程 在shell上同步动态显示当前系统时间
  8. MySQL TIMESTAMP(时间戳)详解
  9. ASP.NET脚本过滤-防止跨站脚本攻击(收集别人的)
  10. golang中defer的使用规则
  11. springboot学习(一)——helloworld
  12. I can do it
  13. 如何在Cocos2D游戏中实现A*寻路算法(三)
  14. ZJOI2018 D1T2 历史(毕竟我菜,所以题解十分易懂。。)
  15. php 批量下载文件
  16. 淘宝bug bug bug
  17. 第二章 flex输入输出
  18. css学习_css书写规范
  19. C# 测试代码段性能耗时
  20. Zuul Timeouts

热门文章

  1. 使用Fluentd + MongoDB构建实时日志收集系统
  2. Python学习之路day3-文件操作
  3. eclipse部署和启动guns
  4. 安装Aptana时检测不到已经安装的Nodejs
  5. Java进阶知识点2:看不懂的代码 - 协变与逆变
  6. 三、Jmeter--HTTP请求默认值(HTTP Request Defaults)和访问地址参数化
  7. Eureka详解
  8. 解决IDEA输入法不跟随
  9. 如何修改MAC自带的PHP的版本?
  10. 蓝桥杯 基础练习 BASIC-14 时间转换