V8引擎内存机制

内存大小和操作系统有关: 64位-1.4G 32位-0.7G

64位系统下的新生代内存-64MB 老生代内存-1400MB

32位系统下的新生代内存-16MB 老生代内存-700MB

为什么限制内存大小?

1、够用了,js设计的初衷是浏览器脚本语言,只执行一次,便释放内存

2、如果不限制,回收一次100MB的内存大概花费3ms,V8引擎在回收垃圾时,是暂停住所有代码的执行,一旦垃圾过多,在回收内存的时候,中断的时间过长,体验不佳。

新生代内存:保存新变量,存活时间短的

老生代内存:保存老变量,存活时间长的(老变量:经过几次垃圾回收也没有被杀死的变量)

新生代变量晋升老生代变量的条件:①这个变量经历过内存回收,当未被回收 ②新生代内存空间一旦超过占用临界值,①中的变量就会被移到老生代内存中

新生代内存特点:内存回收频率快,因为频率快,所以要求回收这个动作要快,即持续时间短,所以采用了牺牲空间换取时间的算法。

在这里插入图片描述

新生代内存回收机制

假设所有新变量都存在From中,那么在回收的过程中,会先标记活变量,将活着的变量全部复制到To当中,清空From,第二次回收时,标记活变量,将活着的变量全部复制到From当中,清空To 也就是:标记-复制-清空的过程

老生代内存回收机制

假设在内存中有一片连续的区域:1,2,3,4,5 此时2,4死亡,标记并删除后,内存变为:1,-,3,-,5 这时内存空间会不连续,也就是所谓的内存碎片,如果不进行修补,有可能会放不进数组,因为在数据结构中,数组中的元素是储存在内存中的连续一片地址中的。所以在V8引擎中,老生代内存在标记-删除之后,还要进行一次排列,整理内存碎片。

标记死亡变量,删除死亡变量,整理内存空间 也就是标记-删除-整理的过程

新生代内存:标记-复制-清空(省时,费空间) 老生代内存:标记-删除-整理

内存回收时机

在这里插入图片描述

在内存占用接近临界值的时候,开始回收内存

全局变量:只在程序执行完成才会被回收,否则永久保留

查看内存的方法:

浏览器: window.performance

一段代码:Node-process.memoryUsage()

function getMemory() {
    
    
  var memory = process.memoryUsage();
  var format = function(bytes){
    
    
    return (bytes/1024/1024).toFixed(2)+"MB"
  }
  console.log('heapTotal'+ format(memory.heapTotal)+ '        heapUsed'+ format(memory.heapUsed))
}

查看内存使用情况

function getMemory() {
    
    
  var memory = process.memoryUsage();
  var format = function(bytes){
    
    
    return (bytes/1024/1024).toFixed(2)+"MB"
  }
  console.log('heapTotal'+ format(memory.heapTotal)+ '        heapUsed'+ format(memory.heapUsed))
}

var a = []
var size = 20*1024*1024
function b() {
    
    
  var arr1 = new Array(size)
  var arr2 = new Array(size)
  var arr3 = new Array(size)
  var arr4 = new Array(size)
}
b()
getMemory()
setInterval(()=>{
    
    
  a.push(new Array(size))
  getMemory()
},1000)

在控制台中执行 node xx.js 便可看到内存的变化情况

容易引发内存使用不当的情景:①滥用全局变量 ②缓存不限制 ③操作大文件

全局变量能不用就不用,如果必须要用,就要在用完之后释放掉内存,不用delete,因为在strict模式下会有意想不到的bug,直接将该全局变量置为undefined

一般缓存也是定义一个全局变量,将一些数据放到缓存对象中,这是一般做法,但是如果是个持久化的操作,会不断往缓存中放东西,也会有内存不足的危险。所以要给缓存加上限制。

不给缓存加上限制的情景:

var a = []
var size = 30 * 1024 * 1024
for (let i = 0; i < 16; i++) {
    
    
  a.push(new Array(size))
}

其中 a 为缓存对象,size是模拟数组的大小,这是循环往a中不断放一个超大数组,在16次之内,已经能造成内存不足,导致程序无法进行下去了。

给缓存加上限制:

var a = []
var size = 30 * 1024 * 1024
for (let i = 0; i < 16; i++) {
    
    
  if(a.length < 4){
    
    
  a.shift()
  }
  a.push(new Array(size))
}

在不断往a中放数据的时候,加上判断,如果a中超过4个元素,就将第一个元素去掉这样就保证缓存不会一直在变大。

性能优化

lighthouse:谷歌的一个插件

回报代码:window.performance 中有详细的性能数据信息,可以在公共模板中使用这些数据,再通过ajax或其他方式发送给后端的某个监听接口,有后端来让这些数据可视化。

猜你喜欢

转载自blog.csdn.net/michaelxuzhi___/article/details/106224978