Node.js专题

Node.js内存管理基础讲解

2019-06-01  本文已影响6人  程序员成长指北

Node与V8

3)V8的对象分配

V8中,所有的javaScript对象都是通过堆来进行分配的。V8的堆内存包括heapToal(已经申请到的堆内存),heapUsed(当前使用的堆内存);我们在代码中声明变量并赋值的时候,所使用的对象的内存就分配在堆中。如果已申请的堆空闲内存不够分配新的对象,将继续申请堆内存,直到堆的大小超过V8的限制为止。

说明:基于V8这种限制将会导致Node无法操作大内存对象,也因此后来出现了buffer这种不受V8丢内存控制的堆外内存管理。

开发过程中的那些不好回收的内存(高效使用内存)

由于V8已经对内存做了限制,我们应该做到高效的使用内存,让垃圾回收机制更高效的工作,避免一些不容易回收内存的出现。

var a=function(){
    var local={};
}

函数a在每次被调用的时候会创建对应的作用域,函数执行结束后,该作用域将会销毁。同时因为该作用域中声明的局部变量分配在该作用域上,随作用域的销毁而销毁。只被局部变量引用的对象存活周期较短。代码中,由于对象较小,将会分配在新生代的Form空间中。作用域失效后,局部变量local失效,其引用的对象将会在下次垃圾回收时被释放。

2)作用域中的变量查找

JavaScript在执行时会查找变量定义在哪,最先查找的当前作用域,当前作用域没有,会向上级的作用域查找,直到最顶层全局作用域查到,如果没有最后返回undefine。

3)变量的主动释放

如果变量是全局变量(通过var声明或定义在global变量上),全局作用域直到进程退出才能释放,这种情况将导致引用的对象常驻内存(常驻在老生代中)。这种需要释放常驻内存中的对象,可以使用delete操作来删除引用关系,或者将变量重新赋值,让旧对象脱离引用关系(也就是对象的引用即所占的内存空间原本指向某个变量现在指向空获未定义),这样在接下来的老生代内存 清 除和整理的过程中会被释放。

global.foo="i am gang";
console.log(global.foo);// i am gang

delete global.foo;

//或者重新赋值
global.foo=undefined;// or null
console.log(global.foo);//undefined

说明:虽然两种方式都可以主动释放变量引用的对象(也就是那一小块内存),但是推荐大家使用重新赋值的方法,因为在V8中通过delete删除对象的属性有可能干扰V8的优化。

var A=function(){
    (function(){
        var local="局部变量";
    }());
    console.log(local); //local未定义异常
}

var B=function(){
    var C=function(){
        var local="局部变量";
        return function(){
            return local;
        };
    };
    var c=C();
    console.log(c()); //局部变量
};

分析第二段代码,函数C执行完成后,局部变量local会随着作用域的销毁而被回收。但是注意这里的特点是返回值是一个匿名函数,而且这个函数中具备了访问local的条件,后面的代码执行,外部作用域是无法直接访问local的,但是若要访问它,只要通过这个中间函数稍作周转即可。以上就是闭包的基本分析,现在能够更好的理解我画重点的那句话了吧。

对于闭包的详细介绍,大家可以看我的这篇博客javascript中的闭包这一篇就够了

内存相关基本命令使用

$ node
> process.memoryUsage();
{
    rss:14958592,
    heapTotal:7195904,
    heapUsed:2821496
}

heapTotal:V8中已申请的堆内存

heapUsed:V8中当前使用的堆内存

rss:进程的常驻内存部分

$ node
> os.totalmem()
82132131
> os.freemem()
31273127

os.totalmem 操作系统的总内存

os.freemem 操作系统的闲置内存

var useMem=function(){
    var size=200*1024*1024;
    var buffer=new Buffer(size);
    for(var i=0;i<size;i++){
        buffer[i]=0
    }
    return buffer;
};

代码执行过程中,查看内存使用情况会发现到最后,V8的使用内存heapUsed和申请的内存heaptotal基本不变,而常驻内存rss在不断增加,可以看出buffer对象不同于其它对象,不经过V8内存分配机制,不会有堆内存的限制。后面的文章会对buffer进行详细的讲解。

内存泄露

Node对内存泄漏十分敏感,一旦线上应用有成千上万的流量,哪怕一个字节的内存泄漏也会造成堆积,垃圾回收过程中将会耗费更多时间进行对象扫描,应用响应缓慢,直到进程内存溢出,应用奔溃。

内存泄漏这里有一个点,我们每次把服务重启的时候会不会这个内存泄漏的堆积重新开始计算,forever restart和forever stop之后在forever start

觉得本文对你有帮助?请分享给更多人

我的公众号.jpg

欢迎大家关注我的公众号——程序员成长指北。请自行微信搜索——“程序员成长指北”

上一篇 下一篇

猜你喜欢

热点阅读