首先声明一下,这个内存控制指的是V8引擎的内存控制,听起来很高大上,平时web开发可能不会去考虑浏览器的内存控制机制,但是其实我们在学习js的时候就有多少了解到垃圾回收和内存监控这相关的知识。
Js的垃圾回收机制和内存控制
在《JavaScript高级程序设计》(第三版)里也有提到了js的垃圾回收机制和内存回收问题,这里简单的回想一下:
我们知道,js和java的一个共同点就是有自己的垃圾回收机制,所以他们不用像C/C++程序员一样在编写代码的时候去关心内存的分配与释放的问题。关于js的垃圾回收机制,主要有以下两种:
- 标记清除: 这个很容易理解,就是当你在函数内声明一个变量,那么在函数执行的时候,就将该变量进行标记,标记为进入,函数执行完毕就标记为离开,进入标记的是不可以被回收的
- 引用计数: 更简单的,就是一个变量被使用的次数,用到一次就加一,数目小于多少的就给予清除
那么如何管理内存呢?
前面也说了,因为有自动的垃圾回收机制,所以程序员不用去操心内存管理的问题,但是要注意的一点就是,js的可用内存是很小的,或者说是远远小于桌面程序的可使用内存(这个后面再说),所以为了确保占用最少的内存可以让页面获得更好地性能,最佳方式就是为执行中的代码只保存必要的数据,一旦数据不再有用,就将其释放(比如设置其值为null来释放引用),这样做的目的是解除变量的引用从而使垃圾收集机制在下次运行时将其回收(垃圾回收机制是按照固定的时间间隔或者预设的时间进行处理的,所以这个时间的长短也要考虑性能问题)
V8的内存分配
那么说完了js中的内存管理,那么就到了我们今天讨论的V8引擎,浏览器内的内存控制。
内存限制
首先呢,通过Node使用内存时是只可以使用部分内存的,这个大小大概在(64位系统下是1.4GB,32位系统下是0.7GB),在V8中,所有的js对象都是通过堆来进行分配的,这个可以通过控制台输入 process.memoryUsage() 方法查看。执行此操作需要切换到node命令执行环境。
V8的内存分配
在V8中,主要将内存分为新生代和老生代两种,新生代中的对象为存活时间比较短的对象,老生代中的对象为存活时间较长或常驻内存的对象。V8的堆内存的大小就是新生代加上老生代的大小。而V8关于内存限制的算法主要有两种,这里只简单提及一下。
一种是牺牲空间换时间的算法,叫做Scavenge算法,通过该算法来回收新生代中的对象,原理就是讲新生代的内存一分为二,A和B,A和B永远都是一个处于空闲状态,一个处于使用状态,在垃圾回收的时,会检查使用中的A,如果A中存在还使用的对象啥的,就复制给空闲中的B,然后A中没有被使用对象啥的就会被清除,如此往复,达到垃圾清除的目的,但是这个算法有一个问题就是,如果A中存活的还在使用的对象是比较少的,那么在进行复制时,这个效率是很高的,但如果A中存活的对象比较大,效率就不能满足需求了。
这就牵扯到另外一种算法了,另外一种就是 Mark-Sweep 和 Mark-Compact ,标记清除方法,这个很简单,就是没有一分为二的概念,直接查找内存中的存活或者死亡的对象,然后添加一个标记,然后等垃圾回收进行清除,需要注意的一点,为了避免标记清除造成的内存碎片化,需要在对象被标记死亡后进行一次整理,将或者的对象往一端靠拢,举个例子就是好人站内存左边,坏人站内存右边,等会收拾坏人。
如何高效的使用内存
这一块儿呢,只需要注意作用域和闭包带来的问题就好,跟js中的优化是一样的,不作介绍。
内存泄漏
内存泄漏是程序员在与内存打交道时一定要注意的问题,通常情况下,造成内存泄露的原因主要有三个: 缓存、 队列消费不及时、 作用域未释放。
基于此,避免造成内存泄漏的方案也有以下两种:
- 不要将内存当做缓存: 说不要太过了,尽量不要吧;
- 关注队列状态: 队列状态造成的内存泄漏其实不容易发生,因为大多数情况是使用的速度是大于生产的速度的,是不会有库存的。但是二班情况,如果出现了,就很难排查,所以对于队列状态引起的内存泄漏,应监控队列的长度,如果长度超过了一定限制,就给出异常拒绝再使用内存。
前端新手,弱鸡一枚,如有错误,请指正,谢谢!