v8的内存管理算法---如何管理内存

为什么要关注内存:

1、防止页面占用内存过大,引起客户端卡顿,甚至无响应

2、Node使用的也是V8,内存对于后端服务的性能至关重要。因为服务的持久性,够短更容易造成内存溢出。

3、面试装逼神器(哈哈哈)

v8引擎内存回收机制

一、v8引擎内存分配

分为:新生代内存空间,老生代内存空间

内存大小:

  和操作系统有关,64位为1.4G,32位为0.7G;64位下新生代的空间为64M,老生代为1400M;32位下新生代为16M,老生代为700M。

  为什么是1.4G呢?

  1、js最初设计是在浏览器上跑的,浏览器上的js不持久,1.4G安全够用,

  2、js回收垃圾的时候,会暂停所有代码的执行,如果内存过大,回收时占用的时间会更多,300mb  回收 0.5秒

  为什么新生代内存空间划分成两块呢(一个from,一个to)?

  先说一下垃圾回收算法:

    新生代回收算法简单的说就是复制:

      新生代内存空间,会标记活着的变量,典型的牺牲空间获取时间的方式
      该内存空间中主要存一些新的变量、存活时间较短的变量,会频繁的进行垃圾回收

    老生代回收算法就是标记删除整理:

      老生代标记死了的变量,需要整理磁盘碎片,新生代不需要整理,效率更高
 
二、v8是如何处理变量的
1、如何查看内存使用情况

  通过node来查看内存使用情况:process.memoryUsage();

    {

      rss: 22347776,             //v8申请到的总占用空间
      heapTotal: 9682944,     //堆总内存
      heapUsed: 5401712,    //已经使用了的内存
      external: 16901            // node底层是C++,他可以申请到一些C++的内存

    }

  通过浏览器来查看内存:

    F12调试工具查看;performance

    控制台输入:window.performance  // 可以查看到当前页面的各种内存情况

function getmem(){
    var mem = process.memoryUsage();
    var format = function(bytes) {
         return (bytes/1024/1024).toFixed(2) + 'MB';
    };
    console.log('Process: heapTotal ' + format(mem.heapTotal) + '  heapUsed  ' + format(mem.heapUsed) + '  rss  ' + format(mem.rss));
};

 

2、内存处理

  内存主要就是存储变量等数据结构的

  局部变量当程序执行结束,并且引用的时候就会随着消失

  全局对象会始终存货到程序运行结束

//  局部变量没有引用之后会被销毁
//  没有返回值,函数调用完了变量就会被销毁了
var size = 20*1024*1024;
function a(){
    var arr1 = new Array(size);
    var arr2 = new Array(size);
    var arr3 = new Array(size);
    var arr4 = new Array(size);
    var arr5 = new Array(size);
    var arr6 = new Array(size);
    var arr7 = new Array(size);
    var arr8 = new Array(size);
    // var arr9 = new Array(size);
    // return [arr1,arr2,arr3,arr4,arr5,arr6,arr7,arr8];
}
a();
getmem();    // Process: heapTotal 1288.83MB  heapUsed  1283.34MB  rss  1299.79MB
var  arr9 = new Array(size);


// 有返回值的函数
var size = 20*1024*1024;
function a(){
    var arr1 = new Array(size);
    var arr2 = new Array(size);
    var arr3 = new Array(size);
    var arr4 = new Array(size);
    var arr5 = new Array(size);
    var arr6 = new Array(size);
    var arr7 = new Array(size);
    var arr8 = new Array(size);
    // var arr9 = new Array(size);
    return [arr1,arr2,arr3,arr4,arr5,arr6,arr7,arr8];
}
a();
getmem();    // Process: heapTotal 1288.83MB  heapUsed  1283.34MB  rss  1299.76MB
var  arr9 = new Array(size);
// 函数只是return 了一个值,最后的执行结果与第一种情况没很大的差别

// 当将返回值赋值给一个变量后,变量保留了这一系列数组的引用,最后崩了
// var  c = a();

  

 

三、如何注意内存的使用

1、优化内存的技巧:

  尽量不要定义全局变量

  全局变量要记得销毁掉

  用匿名自执行函数变全局为局部

  尽量避免闭包 --- 错误的????(闭包不会影响内存了)

// 全是全局变量
// 全局变量记得要销毁:delete arr (不推荐使用,在严格模式下回出现很多问题);
// arr1 =undefined; arr1 = null;
var size = 20*1024*1024; var arr1 = new Array(size); var arr2 = new Array(size); var arr3 = new Array(size); var arr4 = new Array(size); var arr5 = new Array(size); var arr6 = new Array(size); var arr7 = new Array(size); var arr8 = new Array(size);
arr1 = null; // 定义9之前吧1释放掉,也不会报错了
var arr9 = new Array(size);
getmem(); // 运行结果:Process: heapTotal 1288.83MB heapUsed 1283.34MB rss 1299.75MB // 当有9个时,会报内存泄漏错误

  

var size = 20*1024*1024;
// 用匿名自执行函数包裹起来,让整个代码编程局部的
// (function(){

// })();
(function(){var arr1 = new Array(size)})();

  

// 闭包???
for(var i=10000;i<10100;i++){
    setTimeout(function(){
        console.log(i);
        getmem();
    })
}

// 运行结果:
// 10100
// Process: heapTotal 6.73MB  heapUsed  4.12MB  rss  19.32MB
// 10100
// Process: heapTotal 9.73MB  heapUsed  3.94MB  rss  19.70MB
// 10100


for(var i=10000;i<10100;i++){
    (function(i){
        setTimeout(function(){
            console.log(i);
            getmem();
        })
    })(i)
}

// 运行结果:
// 10000
// Process: heapTotal 9.73MB  heapUsed  3.94MB  rss  19.72MB
// 10001
// Process: heapTotal 9.73MB  heapUsed  3.95MB  rss  19.75MB
// 10002
// Process: heapTotal 9.73MB  heapUsed  3.95MB  rss  19.75MB

// 两种方式的结果相差无几
// v8引擎,闭包基本不会影响内存了

 

2、防止内存泄漏

  滥用内存

// node 服务是持久化的,
var http = require('http');
global.a = [];
var size = 20*1024*1024;
// 创建一个服务
http.createServer((req,res) => {
    function getmem(){
        var mem = process.memoryUsage();
        var format = function(bytes) {
             return (bytes/1024/1024).toFixed(2) + 'MB';
        };
        console.log('Process: heapTotal ' + format(mem.heapTotal) + '  heapUsed  ' + format(mem.heapUsed) + '  rss  ' + format(mem.rss));
    };
    // 每一次请求服务都会往a里面push一个数组,
    a.push(new Array(size));
    getmem();
    res.end('hello world');
}).listen(3000);

// 每刷新一次,内存占用情况就会变化一次
//  运行结果:
Process: heapTotal 169.75MB  heapUsed  164.44MB  rss  180.45MB
Process: heapTotal 329.76MB  heapUsed  324.59MB  rss  340.71MB
Process: heapTotal 490.27MB  heapUsed  484.00MB  rss  500.91MB
Process: heapTotal 650.28MB  heapUsed  644.06MB  rss  661.03MB
Process: heapTotal 810.29MB  heapUsed  804.00MB  rss  821.28MB
Process: heapTotal 970.30MB  heapUsed  964.01MB  rss  981.30MB
Process: heapTotal 1130.32MB  heapUsed  1124.03MB  rss  921.40MB
Process: heapTotal 1290.33MB  heapUsed  1284.02MB  rss  1287.71MB
再来一次就宕机了
// 所以后端特别关注内存


    // 每一次请求服务都会往a里面push一个数组,
    // 为了保证内存不泄露,在push之前,可以加一道锁,判断,当a的长度大于4时,就将第一个元素移除
    if(a.length > 4){
        a.shift();
    }

  

  大内存量操作

    分片、断点

    <input type='file' />

    readfile()  ,createReadStream,避免一次性读取过大的文件(避免一次性超大内存操作)

 

posted @ 2019-10-19 22:27  1220x  阅读(585)  评论(0编辑  收藏  举报