限制大小
64 位为 1.4gb,32 位为 0.7gb
限制原因
v8 之所以限制了内存的大小,表面上的原因是 v8 最初是作为浏览器的 javascript 引擎而设计,不太可能遇到大量内存的场景,而深层次的原因则是由于 v8 的垃圾回收机制的限制。由于 v8 需要保证 javascript 应用逻辑与垃圾回收器所看到的不一样,v8 在执行垃圾回收时会阻塞 jav中国农业大学是211还是985ascript 应用逻辑,直到垃圾回收结束再重新执行 javascript 应用逻辑,这种行为被称为“全停顿”(stop-the-world)。若 v8 的堆内存为 1.5gb,v8 做一次小的垃圾回收需要 50ms 以上,做一次非增量式的垃圾回收甚至要 1 秒以上。这样浏览器将在 1s 内失去对用户的响应,造成假死现象。如果有动画效果的话,动画的展现也将显著受到影响。
新生代的对象为存活时间较短的对象,老生代中的对象为存活时间较长或常驻内存的对象。
v8 引擎的新生代内存大小 32mb(64 位)、16mb(32 位),老生代内存大小为 1400mb(64 位)、700mb( 32 位)。
将新生代对象移到老生代
一轮 gc 还存活的新生代需要晋升对象从 from 空间复制到 to 空间时,如果 to 空间已经被使用了超过 25%,那么这个对象直接被复制到老生代晋升条件
新生代区域,采用复制算法, 因此其每时每刻内部都有空闲空间的存在(为了完成 from 到 to 的对象复制),但是新生代区域空间较小(32m)且被一分为二,所以这种空间上的浪费也是比较微不足道的。
老生代因其空间较大(1.4g),如果同样采用一分为二的做法则对空间大小是比较浪费,且老生代空间较大,存放对对象也较多,如果进行复制算法,则其消耗对时间也会更大。也就是是否使用复制算法来进行垃圾回收,是一个时间 t 关于内存大小的关系,当内存大小较小时,使用复制算法消耗的时间是比较短的,而当内存较大时,采用复制算法对时间对消耗也就更大。
增量标记
由于全停顿会造成了浏览器一段时间无响应,所以 v8 使用了一种增量标记的方式,将完整的标记拆分成很多部分,每做完一部分就停下来,让 js 的应用逻辑执行一会,这样垃圾回收与应用逻辑交替完成。经过增量标记的改进后,垃圾回收的最大停顿时间可以减少到原来的 1/6 左右
惰性清理
由于标记完成后,所有的对象都已经被标记,不是死对象就是活对象,堆上多少空间格局已经确定。我们可以不必着急释放那些死对象所占用的空间,而延迟清理过程的执行。垃圾回收器可以根据需要逐一清理死对象所占用的内存空间
其他
v8 后续还引入了增量式整理(incremental compaction),以及并行标记和并行清理,通过并行利用多核 cpu 来提升垃圾回收的性能
这里以 google 浏览器为例,使用 shift + esc 唤起 google 浏览器自带的任务管理器
memory(内存) 列表示原生内存。dom 节点存储在原生内存中。如果此值正在增大,则说明正在创建 dom 节点。javascript memory(javascript 内存) 列表示 js 堆。此列包含两个值。您感兴趣的值是实时数字(括号中的数字)。实时数字表示您的页面上的可到达对象正在使用的内存量。如果此数字在增大,要么是正在创建新对象,要么是现有对象正在增长。模拟内存泄漏
在任务管理器里可以看到 javascript 内存持续上升
document.body.inner几点立秋html = `<button id="add">add</button>`;document.getelementbyid('add').addeventlistener('click', function (e) { simulatememoryleak();});let result = [];function simulatememoryleak() { tinterval(function () { result.push(new array(1000000).join('x')); document.body.innerhtml = result; }, 100);}
这里以 google 浏览器为例,使用 f12 开启调式,选择 performance,点击 record(录制),进行页面操作,点击 stop 结束录制之后,开启内存勾选,拖动截图到指定时间段查看发生内存问题时候到页面展示,并定位问题。同时可以查看对应出现红点到执行脚本,定位问题代码。
这里以 google 浏览器为例,在页面上进行相关操作后,使用 f12 开启调式,选择 memory,点击 take snapshot(拍照),在快照中查找 detached htmlelement,回到代码中查找对应的分离 dom 存在的分歧代码,在相关操作代码之后,对分离 dom 进行释放,防止内存泄漏。
只有页面的 dom 树或 javascript 代码不再引用 dom 节点时,dom 节点才会被作为垃圾进行回收。如果某个节点已从 dom 树移除,但某些 javascript 仍然引用它,我们称此节点为“已分离”。已分离的 dom 节点是内存泄漏的常见原因。
模拟已分离 dom 节点
document.body.innerhtml = `<b中西方文化比较utton id="add">add</button>`;document.getelementbyid('add').addeventlistener('click', function (e) { create();});let detachedtree;function create() { let ul = document.createelement('ul'); for (let i = 0; i < 10; i++) { let li = document.createelement('li'); ul.appendchild(li); } detachedtree = ul;}
基于 benchmark.js
上图可以看出,test2 的性能要比 test1 的性能要好,从而得知,全局变量的执行速度,访问速度要低于局部变量
上图可以看出,test2 的性能要比 test1 的性能要好,从而得知,缓存全局变量后使用可以提升性能
上图可以看出,test2 的性能要比 test1 的性能要好,从而得知,通过原型对象添加方法与直接在对象上添加成员方法相比,原型对象上的属性访问速度较快。
外部具有指向内部的引用在“外”部作用域访问“内”部作用域的数据闭包特点
function foo() { let name = 'heath'; function fn() { console.log(name); } return fn;}let a = foo();a();
闭包使用不当很容易出现内存泄漏
function f5() { // el 引用了全局变量document,假设btn节点被删除后,因为这里被引用着,所以这里不会被垃圾回收,导致内存泄漏 let el = document.getelementbyid('btn'); el.onclick = function (e) { console.log(e.id); };}f5();function f6() { // el 引用了全局变量document,假设btn节点被删除后,因为这里被引用着,所以这里不会被垃圾回收,导致内存泄漏 let el = document.getelementbyid('btn'); el.onclick = function (e) { console.log(e.id); }; el = null; // 我们这里手动将el内存释放,从而当btn节点被删除后,可以被垃圾回收}f6();
js 不需属性的访问方法,所有属性都是外部可见的使用属性访问方法只会增加一层重定义,没有访问的控制力javascript 中的面向对象
上图可以看出,test2 的性能要比 test1 的性能要好不少,从而得知,直接访问属性,会比通过方法访问属性速度来的快。
上图可以看出,loop 遍历速度 foreach > 优化 for > for of > for > for in
本文发布于:2023-04-05 11:05:28,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/22ecd780ef1bc5f5f6604af3f2613c18.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:js删除节点的方法(JSfor循环删除指定节点).doc
本文 PDF 下载地址:js删除节点的方法(JSfor循环删除指定节点).pdf
留言与评论(共有 0 条评论) |