02 您所在的位置:网站首页 node底层语言 02

02

2023-03-14 22:53| 来源: 网络整理| 查看: 265

02-v8引擎回收内存

为什么学习内存:

前端:防止前端界面内存占用过大,造成界面卡顿甚至无响应

后端:Node 使用的也是V8引擎,内存对于后端服务的性能很重要。后端服务的持久性和健壮性,后端很容易造成内存溢出。

为什么前端要了解底层?现在前端的技术全面性很重要。不一定要使用express完成服务器端框架设置,但是需要了解原理(增加竞争力)。

1、V8 引擎 GC 机制

V8的内存分为新生代内存空间和老生代内存空间(新生代很小)。V8引擎内存和操作系统相关,64位操作系统1.4G(64MB+1400MB),32位系统0.7G(16MB+700MB)。

为什么设计成1.4G?

JS最初设计为了前端,需要的数据不是持久性的,执行一次就GC,1.4足够JS 执行 GC 时,会暂停脚本执行,如果太呆,GC消耗时间

新生代和老生代数据区别?

新生代存放短期的最新的数据,老生代存放较老的数据。数据转换:如果新生代的某个数据(数组)已经经过一次GC,同时新生代To空间已经使用了25%,那么这个新生代数据就放在老生代中。

GC 算法区别:

新生代内存处理算法:复制,新生代内存分成两部分(from-to)首先在一个部分存放变量。当V8觉得需要清空内存时,将存放变量部分中有用的变量复制到另一个区域中,然后清空这个区域。下一次清空内存时,操作对调。牺牲了空间复杂度(只使用一半内存),优化了时间复杂度(直接复制)。

老生代内存处理算法:标记、删除、整理三步:标记有用的内存和无用的内存,删除无用的内存,把离散的有用的内存整理成连续的有用的内存。为什么要整理内存,把离散的内存占用整理成连续的内存占用?因为一部分变量需要连续的内存(例如数组,如果都是分散的内存地址,那么无法创建新的变量)

在node环境下可以直接使用JS代码判断内存。Node 用C++写的,所以可以手动扩展内存。在浏览器中不能扩展内存。

以前的知识体系中,闭包会影响内存的清理。现在的技术可以解决这个问题。所以看书的时候一定注意书籍的时间效应(视频课程也一样)。

2、查看V8内存使用情况 node环境

查看内存使用情况 process.memoryUsage() 直接执行

console.log(process.memoryUsage());

获取下面的信息

{ rss: 21417984, heapTotal: 7159808, heapUsed: 4447496, external: 8224 }

为了便于阅读,我们使用下面的函数转换成 MB

var format = function(bytes) { return (bytes / 1024 / 1024).toFixed(2) + 'MB'; } function getMemory() { var mem = process.memoryUsage(); var str1 = 'Process: heapTotal ' + format(mem.heapTotal); var str2 = 'heapUsed ' + format(mem.heapUsed); var str3 = 'rss ' + format(mem.rss); return str1 + str2 + str3; } 浏览器环境

在浏览器环境中 window.performance

window.performance.memory

totalJSHeapSize/usedJSHeapSize/jsHeapSizeLimit 判断使用的比例

V8如何处理变量和内存呢?

内存主要用于存储数据(变量)。变量分为全局变量和局部变量:全局变量始终存在,直到程序运行结束;局部变量会当程序执行结束,并没有外部引用的时候,就会删除变量,释放内存。

// 避免使用很多全局变量 var size = 20 * 1024 * 1024; var arr = new Array(size); // 使用函数避免全局变量 function b() { var arr = new Array(size); } b();

test.js

var http = require('http'); var a = []; http.createServer(function() { function getMe() { // } a.push(new Array(20 * 1024 * 1024)); getMe(); }).listen(3000); 3、内存优化实例 尽量不定义全局变量全局变量使用后要销毁匿名函数自执行把全局变量转换成局部变量尽量避免闭包后外部引用

销毁变量时,推荐使用 null undefined,不使用 delete(在严格模式下有问题);对于React,在组件卸载阶段,或者不使用这个全局变量时,就移除这个变量,释放内存。

如何放置内存泄漏?

避免滥用缓存:当缓存的内容很多(判断缓存数组的长度),清空早期的缓存数据,加一个锁提示缓存过多(实际项目中的undo-redo存储这操作) let cache = []; // 缓存通常存放在全局 // 数据操作后放入缓存 // cache.push(item); // 如果缓存很大,清空一部分缓存 if (cache.length > 10) { cache.shift(); } // 组件卸载时清空缓存 cache = null; 减少大内存操作:前端上传大文件使用分片长传技术;后端文件流技术。前端需要把大文件流,调用 slice 方法后切片,然后循环上传,这样可以避免大量内存(如果上传一个5G的文件,切片上传) import { createReadStream, write } from 'fs'; fs.readFile(); // readFile 是一次性读取文件到buffer,适合小文件上传 createReadStream().pipe(write); // 上传大文件使用切片方法: file 是一个 blob 对象,具有 slice 方法 file.slice(0, 1000); file.slice(1000, 2000);


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有