|

Aimee

Write the Code. Change the World.

垃圾回收机制

· 分享镜#h5#node

为什么要关注内存?

  • 防止页面内存占用过大,导致客户端卡顿,甚至没有响应
  • Node使用的也是v8,内存对后端服务的性能至关重要。因为服务的持久性,后端更容易造成内存溢出。

栈空间

栈空间是临时空间,主要存储局部变量和函数调用。 基本类型赋值(Number/String/Boolean/Null/Undefined/Symbol/BigInt),系统会为新的变量在栈内存中分配一个新的值。 ​ 引用类型赋值,系统会为新的变量在栈内存中分配一个值,这个值仅仅是指向同一个对象的引用,和原对象指向的都是堆内存中的同一个对象。

对于函数,解释器创建了调用栈来记录函数的调用过程。每调用一个函数,解释器就把该函数添加到调用栈,解释器会为被添加进来的函数创建一个栈帧(用来保存函数的局部变量和执行语句)并立即执行。如果正在执行的函数还调用了其他函数,新函数会被继续添加到调用栈。函数执行完成,对应的栈帧立即被销毁。 ​ 栈溢出 栈不是可以无限增长的,被分配的调用栈空间被占满时,就会引起栈溢出的错误。 如下:

(function foo(){
  foo()
 })()
// Uncaught RangeError: Maximum call stack size exceeded

为什么基础数据存放在栈中,引用数据类型存放在堆中? js引擎需要用栈来维护程序执行期间的上下文状态,如果栈空间大了的话,所有数据都存放在栈空间里面,会影响到上下文切换的效率,进而影响整个程序的执行效率。 ​

堆空间

大致分为新生代、老生代、大对象区、单元区属性单元区Map区、代码区。 垃圾回收算法 变量 => 新生代 =>老生代


    ------------------------------------------
    |                                        |
    |       Resident Set 所有内存占用          |
    |                                        |
    |      ----------------------------      |
    |      |  代码区域 Code Segment     |      |
    |      ----------------------------      |
    |                                        |
    |      ----------------------------      |
    |      |  栈(Stack):本地变量、指针  |      |
    |      ----------------------------      |   
    |                                        |
    |      ----------------------------      |
    |      |  HeapTotal(堆):对象,闭包  |      |
    |      |                          |      |
    |      |   ---------------------  |      |   
    |      |   |heapUsed 使用到的堆。|  |      | 
    |      |   |     判断内存泄漏,  |  |      |
    |      |   |   以heapUsed字段为准|  |      |
    |      |   ---------------------  |      |   
    |      |                          |      |
    |      ----------------------------      |
    ------------------------------------------


新生代:

  • 64位 共64mb from和to分别为32mb 32位折半
  • copy复制 scavenge 算法
  • from <=> to 互换

问:新生代为什么要采用复制这种形式呢? 算法一般考虑时间复杂度和空间复杂度,优先考虑时间复杂度,牺牲空间换时间。

老生代:

  • 标记清除mark-sweep:标记、清除
  • 标记整理mark-compact:标记、整理、清除
  • 64位1.4GB 32位 7GB 14版的node内存为2GB

为什么要整理?为什么要先整理后清除? 整理后可以一次清除,整理的时候可以直接覆盖,也就清除了一部分垃圾。 ​ 广度扫描、全停顿标记、增量标记、三色标记 为什么需要连续的内存空间?需要大的空间存放大的变量 ​ 新生代如何晋升到老生代? 在新生代被复制过一次,to空间使用已超过25%,会晋升到老生代。 ​ v8内存的使用情况

  • 浏览器:window.performance.memory 属性
{
  jsHeapSizeLimit: 4294705152
  totalJSHeapSize: 41432924
  usedJSHeapSize: 38893672
}
  • node:process.memoryUsage() 函数
{
  rss: 19550208,  // 所有内存占用,包括指令区和堆栈
  heapTotal: 5533696, // “堆”占用的内存,包括用到的和没用到的
  heapUsed: 2645088, // 用到的堆的部分。判断内存泄漏,以heapUsed字段为准
  external: 778349 // V8引擎内部的C++对象占用的内存
}

​ 设置内存限制:

  • -max-new-space-size 最大 new space 大小,执行scavenge回收,默认16M,单位KM
  • -max-old-space-size,最大 old space 大小,执行MarkSweep回收,默认1G,单位MB

示例:

  • var a = {name:‘yuhua’};这句代码会做如下几步:
    • 将这句代码放入“代码区域 Code Segment”
    • 将变量a放入“栈(Stack):本地变量、指针”
    • 将{name:‘yuhua’}放入“HeapTotal(堆):对象,闭包”
  • 注意:基本数据类型都在栈中,引用类型都在堆中

被标记后的变量是在内存快要满的时候才清理,示例如下:

onst memory = process.memoryUsage()
console.log(memory)
const getMemory = () => {
  const memory = process.memoryUsage()
  // console.log(memory)
  console.log(`heapTotal: ${(memory.heapTotal / 1024 / 1024).toFixed(2)}   heapUsed: ${(memory.heapUsed / 1024 / 1024).toFixed(2)}`)
}

const size = 20 * 1024 * 1024
let count = 0;
const useMem = () => {
  var arr = new Array(size)
  console.log(count++);
  return arr
}
function fun() {
  let arr1 = new Array(size)
  let arr2 = new Array(size)
  let arr3 = new Array(size)
  let arr4 = new Array(size)
  let arr5 = new Array(size)
}

fun()

var total = []
for (let i = 0; i < 12; i++) {
  getMemory()
  total.push(useMem())
}

console.log('success')

输出结果:

{
  rss: 18718720,
  heapTotal: 4509696,
  heapUsed: 2390664,
  external: 782946,
  arrayBuffers: 9386
}
heapTotal: 819.70   heapUsed: 802.76
0
heapTotal: 835.70   heapUsed: 802.76
1
heapTotal: 995.71   heapUsed: 962.76
2
heapTotal: 1155.71   heapUsed: 1122.76
3
heapTotal: 1315.71   heapUsed: 1282.76
4
heapTotal: 1475.72   heapUsed: 1442.76
5
heapTotal: 1635.72   heapUsed: 1602.77
6
heapTotal: 1795.73   heapUsed: 1762.77
7
heapTotal: 1955.73   heapUsed: 1922.77
8
heapTotal: 2115.73   heapUsed: 2082.17 // 删除垃圾
9
heapTotal: 1635.47   heapUsed: 1602.17
10
heapTotal: 1795.48   heapUsed: 1762.17
11
success

评论0

登录后参与评论。

还没有评论,来抢沙发吧。

回到顶部