狗厂员工来面试本想难为一下,结果被虐得连console.log也不敢写了

news2024/11/28 18:38:59

        这次说到的面试题是关于node服务端内存溢出的问题,狗厂员工来面试本想难为一下,现在我连console.log也不敢写了

        关于这道node内存溢出的问题,大哥从以下几个方面讲的,讲完我觉得自己得到了升华,现在搞得连代码也快不敢写了 

目录

一、所谓的1.4G内存空间

1、javascript与java的简单区别

2、V8引擎为什么只能提供1.4G内存空间

二、内存管理

1、栈内存和堆内存

2、所谓的分区 

三、垃圾回收

1、为什么要回收?

2、如何回收?

3、回收策略

四、错误的代码习惯

1、过多的全局变量

2、意外的全局变量

3、引用对象未释放

4、滥用闭包

5、定时器

6、类似array.filter的使用

7、console.log

五、肉眼看不出问题,要善用工具

1、荐使用Easy-Monitor

2、安装依赖

3、植入代码

 4、然后正常npm run dev,

5、植入异常代码

6、启动easy-monitor

7、点击Start按钮

8、也可以在第6步,控制界面选择“CPU”,然后“Start”

六、终极杀招

1、执行pm2

2、pm2 restart all

3、试一试reload


一、所谓的1.4G内存空间

1、javascript与java的简单区别

        编程语言分为编译型语言和解释型语言,javascript是解释型语言,意思就是一边编译一边执行,很显然解释型语言的执行速度是慢于类似于java那些编译型语言的。

2、V8引擎为什么只能提供1.4G内存空间

     为了能够使javascript能够更快速的解析和执行,能够带来更好的用户体验,v8来了。

     node是基于v8构建的,所以Node中使用的对象基本都是通过v8引擎来进行分配和管理的,甚至是垃圾回收。然而v8本身对内存的使用做了限制,在64位操作系统下只能用1.4GB的系统内存。

     一方面是因为v8最初是为浏览器而设计的,对于浏览器页面来说,很少有需要长时间运行或者使用超大内存的场景,所以1.4GB的内存是足够使用的;

     另一方面更重要的原因,v8引擎的垃圾回收机制性能也是有限制的。v8做一次简单的垃圾回收至少需要50ms,而一旦用户量过大的时候,用户流量访问过来运行代码后,要新占用的内存速度远远大于这个50ms回收一次。再垃圾回收过程中,javascript线程会完全暂停,而javascript在当前所在进程中又是单线程的,所以1.4GB也是基于性能的考虑。试想如果分配的是5个GB的内存,那么垃圾回收一次,程序基本就暂停了。

二、内存管理

1、栈内存和堆内存

        程序运行的时候产生栈内存和堆内存。

        栈内存 主要基础数据类型(基本数据类型),局部变量,方法(函数),栈内存由系统分配空间,限定存储的大小,后进先出,访问效率高,或者说查找效率高。

        栈内存用完就会被系统自动回收

        堆内存 主要存全局变量,引用数据类型。动态分配,总存储空间大,查找效率低。v8要回收的就是不用的堆内存。

2、所谓的分区 

        新生区   代码运行时新分配的对象或者存活期较短的对象都会存储到新生区

       老生区   新生区经过垃圾回收就会晋升到老生区。

       大对象区   这里存储超过其他区域大小的大对象,比如一个超级大的map

       代码运行区   这个很好理解,运行代码也是需要空间的。

三、垃圾回收

1、为什么要回收?

        程序在运行时占用了内存,这段程序运行完了并且也不被使用了,没有把占用的内存回收掉,这就形成了一块孤立内存,不断产生孤立内存的过程就可以理解为内存泄漏。由于堆内存是动态分配的,孤立内存占的空间越来越大,这样仅有的1.4GB内存空间就越来越小,然后本来生龙活虎的武林高手在一个狭小的空间胳膊都不能动了,施展不出招式了,然后就被自己运行的内功憋死了。

2、如何回收?

        说的简单点就是v8找到不再使用的变量,然后把这个变量占的内存释放掉。他怎么知道哪些变量不再被使用了呢?

3、回收策略

      △ 标记清除

      当变量进入执行环境时,就标记这个变量为“进入环境”,永远不能清除进入环境的变量占用的内存,因为只要变量进入环境,就有可能会被用到。当变量离开环境时,又被标记为“离开环境”。这个时候就可以清除了。

        △、引用计数,计数为0的,进行清除

        意思就是说有一张表记录了每个变量的被引用的次数。

        执行func返回undefined,按说func obj1 obj2都应该被回收。但里面的变量都被引用了,变量计数都不为0,所以就不能被回收。再看下图可能会加深理解

 

四、错误的代码习惯

1、过多的全局变量

        例如我们一些node java 或者phython的接口里的全局数据,请求完把它存储到global全局存储上,供全局各处需要的地方使用。全局变量是不会被回收的,所以全局变量要少用,不能为了贪图方便到处定义全局变量。当然不用全局变量是不现实的,所以要妥当使用。

2、意外的全局变量

function hello () {

        this.name = "xingyu_qie";

}

          又或者定义变量的时候前面不加修饰符,直接 name = "xingyu_qie"

3、引用对象未释放

        比如上面我们说的,全局存放了一个大的全局对象,然后我们定义一个变量去引用他

let staticVersion = globalData['version'];

          本来staticVersion如果赋值一个基本类型的话,方法走完了就被系统回收了,但却因为引用了一个对象,使栈和堆里面的一个引用产生了关系,这样staticVersion这个变量就不能被回收,甚至导致当前方法都不能被回收。当用完了应该及时staticVersion = null;进行释放

4、滥用闭包

        闭包是最容易造成内存溢出的,因为闭包的逻辑就是方法内外的引用,使某些需要用到的变量被存于缓存中

5、定时器

        同样,代码中避免不了使用setInterval,setInterval和setTimeout不同,setInterval会在队列中生成定时任务,使程序每隔多久去执行一次。这本身也是在开销内存,如果定时任务函数内再包含有其他几种错误使用的话,那内存溢出也是早晚的事情了

6、类似array.filter的使用

const arr = [1, 2, 3, 4, 5]

const myArr = arr.filter((item) => {

        return item === 2;

})

           其实遍历并没有在2的时候break掉,会一直执行到最后,这也是一个很大的开销

7、console.log

const obj = {"name": "xingyu_qie", ...此处省略N行, };

console.log(obj);

          我就是打印了它一下,我啥都没有做啊。正是因为obj这个堆里面的变量,被console.log引用了一次,相当于新定义了一个变量去引用了他一次,和第3条引用对象未释放意思差不多,这就释放不掉了。再如果这个console.log被写在了某个定时器里,这不就更加糟糕了吗

        这是几种典型的会造成的内存溢出的情况,其实还有很多,因为一时疏忽就让某个变量变成了“进入环境”而出不来。

五、肉眼看不出问题,要善用工具

1、荐使用Easy-Monitor

        它有个缺点,做性能分析的时候需要植入代码,但结合其他几种工具,我觉得这个还比较好用。

2、安装依赖

        npm install easy-monitor

3、植入代码

        然后植入代码,在index.ts里加就行

        

 

 4、然后正常npm run dev,

        成功启动后就可以看到easy-monitor打印的日志,如下图

 

5、植入异常代码

        然后加一些很明显影响性能的代码,比如在业务代码里里加,然后访问localhost:3000/ list/detail/10232,看下图,通过对以上的学习,下面的代码是不是很牛,甚至觉得牛到无以复加

        

 

6、启动easy-monitor

        然后该启动easy-monitor管理界面了,新开浏览器页签,访问  http://localhost:12333/index,访问的界面如下图:

 

7、点击Start按钮

        点项目名称后面的“Start”按钮,然后就开始刷第5步打开的页面,使劲儿的刷新吧,不过你再怎么刷新肯定也比不上双11的时候群众们的访问速度,但是如果我们手动刷新都能看出效果,证明代码的确是有问题的。再返回easy-monitory管理界面看,稍微刷新了几次,效果还是挺明显的。然后把对应的js代码删了或者优化一下,再过来试试这个走势图吧。

          heapUsed: 正在使用的堆内存大小

          heapTotal: 当前申请的总堆内存大小

          rss: 堆外分配的内存大小

8、也可以在第6步,控制界面选择“CPU”,然后“Start”

        也可以在第6步,控制界面选择“CPU”,然后“Start”,他会跑5分钟,然后告诉你代码哪里费时间了,耗性能了。我们的那段业务代码里果然有问题,也可以点“MEM”查看对应的耗费内存情况

六、终极杀招

        我们使用了各种招式,线上还是有内存溢出的情况,或者大促期间访问量太大,v8回收的速度跟不上程序创建对象占用内存的速度了,怎么办?

     通过pm2对node服务进行管理,重启服务。

1、执行pm2

        如下图,执行“pm2 list”  获取到当前运行的node进程,得到id 为0,然后重启指定进程,执行命令“pm2 restart 0”

        

2、pm2 restart all

        如果觉得找指定进行麻烦,直接执行“pm2 restart all”,把所有进程都重启了。

3、试一试reload

        其实更多时候不必使用restart的方式,可以使用 “pm2 reload all”,restart是真正的把服务关掉再重启,包含一个stop的过程。而reload是把配置文件重新读一遍重新加载。

如果把restart和reload比作 关闭浏览器再打开 和 F5刷新一下 是不是更形象。

        经过大哥的一顿虐,我幡然醒悟,原来console.log也会造成内存溢出。但这是服务端代码。因为服务端不像浏览器那样可以随时刷新。

        那么C端代码尽量不把console.log带到线上去是为什么呢?我们继续学习。。。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/3589.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2.24 OrCAD Cadence16.6怎么更改原理图中做好的库文件?

笔者电子信息专业硕士毕业,获得过多次电子设计大赛、大学生智能车、数学建模国奖,现就职于南京某半导体芯片公司,从事硬件研发,电路设计研究。对于学电子的小伙伴,深知入门的不易,特开次博客交流分享经验&a…

FPGA代码设计规范一些探讨

代码设计规范的重要性 经过一段的工作积累已经慢慢进入了提高和进阶的阶段,在这篇博客里多聊一聊在现实工作中的话题,比如代码规范以及如何尽快接手前人代码,快速定位项目问题。 显然每个FPGA工程师的设计理念和代码风格很多情况下有一些差别…

python 基于PHP+MySQL的学生成绩管理系统

学生成绩管理是每一个学校都会面临的一个问题,传统的管理模式已经明显到和时代不同步。通过我对当前学校成绩管理的需求和自己的实习经验整理出了一个能够满足大多数学校的学生成绩管理系统。本系统分为管理人员,教师和学生三种用户,每种用户各负责其一部分功能然后通过他们的整…

Web前端开发基础教程二

注释和特殊字符&#xff1a; 如果需要在html文档添加一些便于阅读和理解但又不需要显示在页面中的注释文字&#xff0c;就需要使用注释标签。 html中的注释以“<!--”开头&#xff0c;以“-->”结束或者快捷键&#xff1a;Ctrl/。 举例&#xff1a; <!-- 我想放假 …

【实战】Mysql 千万级数据表结构变更 、含脚本

一、实测结果 业务无感知&#xff0c;无死锁平滑 线上800万数据以下 直接使用 alter 新增字段 300ms左右 2000万数据&#xff0c;强制使用主键索引&#xff0c;每次查询50万数据 并插入新表 &#xff0c;耗时 20s &#xff0c;cpu 占45% 二、整体步骤 创建新表 biz_table_ne…

Vue-脚手架的创建

本篇vue3的脚手架主要是使用vue-cli进行创建&#xff0c;有网的情况下才能创建成功 文章目录一、下载node.js二、全局安装vue/cli三、使用vue-cli创建项目3.1 使用vscode打开终端3.2 创建项目3.3 创建成功四、注意事项一、下载node.js 1、打开node的官网 node官网 2、点击下方图…

Oxygen XML Editor 25.0.X Crack

XML 编辑器 Oxygen XML Editor 是完整的 XML 编辑解决方案&#xff0c;适用于 XML 开发人员和内容作者。它提供了必备的 XML 编辑工具&#xff0c;涵盖了大多数 XML 标准和技术。Oxygen XML Editor 包括 Oxygen XML Developer 和 Author 的所有功能。 特点与技术 单一来源出版 …

【树莓派不吃灰】使用frp内网穿透,实现远程访问树莓派

目录1. 前言2. frp内网穿透2.1 概述2.2 实现原理3. 开源frp项目4. 公网服务器选型5. 下载frp软件5.1 公网服务器下载frp服务器5.1.1 github选择适合服务端的版本5.1.2 公网服务器进行下载解压5.2 树莓派下载frp客户端5.2.1 github选择适合客户端的版本5.2.2 树莓派进行下载解压…

流形上的预积分(上)

预积分和流形 论文&#xff1a;IMU Preintegration on Manifold for Effificient Visual-Inertial Maximum-a-Posteriori Estimation 引言 Recent results in monocular visual-inertial navigation (VIN) have shown that optimization-based approaches outperform filteri…

免费体验CSDN云IDE使用指南

云IDE产品介绍 云IDE使用教程 免费使用地址&#xff1a;点击【云IDE】&#xff0c;即可开始创建工作空间啦~ 官方活动入口 文章目录1.免费体验CSDN云IDE使用指南1.1云IDE优点2.自己的代码在云IDE上跑起来看看如何操作2.1 克隆开源仓库2.2 创建一个空工作空间2.3 使用默认模板代…

Thread类中run和start的区别

一.认识 Thread类 中的 start() 和 run() 首先来看一张jdk-api中对于start 和 run 的描述. 二.方法的区别 下面我们简单看一下代码: // 继承Thread类 重写run() class MyThread extends Thread {Overridepublic void run() {while (true) {System.out.println("thread&q…

如何通过点击商品的信息(图片或者文字)跳转到更加详细的商品信息介绍(前后端分离之Vue实现)

以下只是做简单的演示、大致实现的效果。页面效果需要进一步优化。目的是提供思路 视频效果&#xff1a; 首页商品跳转1、需求 1、首页的的商品来自接口数据2、在首页点击某一个商品跳转到更加详细的商品介绍页面&#xff08;可以购买、加入购物车、查看商品评价信息等&#x…

频频出现的DevOps到底是什么呢?浅浅了解下什么是DevOps吧

文章目录 &#x1f4d1;前言 &#x1f9e9;DevOps的概念和起源 &#x1f4f0;DevOps的概念 &#x1f4f0;DevOps的起源与发展 &#x1f4f0;总结 &#x1f9e9;DevOps的发展 &#x1f4f0;发展过程速览 &#x1f4f0;发展现状 &#x1f4f0;未来发展 &#x1f4c4;以…

【前端】JavaScript数据类型

目录 一、数据类型简介 二、简单数据类型 数字型Number 1.数字型进制 2.数字型范围 3.数字型三个特殊值 4.isNaN() 字符串型String 1.字符串引号嵌套 2.字符串转义符 3.字符串长度 4.字符串拼接 布尔型Boolean Undefined和Null 三、获取变量数据类型 四、数据类型…

res.add(new ArrayList<>(path))和res.add(path)的区别

一.问题描述 在链表path里面添加值&#xff0c;之后把path链表添加到res链表中&#xff0c;自己做的时候使用res.add(path)&#xff0c;结果发现出现解答错误。 题目链接&#xff1a;113. 路径总和 II - 力扣&#xff08;LeetCode&#xff09; 代码如下&#xff1a; class …

网络初始之网络协议

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 目录 文章目录 前言 1.局域网&#xff1a; 概念&#xff1a; 构建方式 2.广域网&#xff1a; 3.IP地址&#xff1a; 4. 端口号&#xff1a; 常考点&#xff1a; 一、…

【单端S参数与差分S参数转化】

单端S参数与差分S参数转化 1 单端S参数说明 对于单端信号来说&#xff0c;用单端S参数来描述其传输特性&#xff0c;如常见的2端口网络&#xff0c;其S参数包括S11&#xff08;1端口回波损耗RL&#xff09;、S21&#xff08;插入损耗IL&#xff09;、S12&#xff08;插入损耗…

[JSON] JSON基础知识

JSON(JavaScript Object Notation&#xff0c;JavaScript对象表简谱)是一种轻量级的数据交换格式&#xff0c;采用完全独立于编程语言的文本格式来存储和表示数据 JSON文件的文件类型是.json JSON是纯文本&#xff0c;具有层级结构&#xff0c;易于阅读和编写&#xff0c;其本…

【愚公系列】2022年11月 微信小程序-优购电商项目-商品支付页面

文章目录前言1. 商品⽀付页面设计规范一、商品支付页面1.业务逻辑2.涉及的接口数据3. 关键技术二、商品购物车页面相关代码1.页面代码2.效果前言 1. 商品⽀付页面设计规范 第一、支付流程一定要简单。现代人的生活节奏是非常快速的&#xff0c;而且情绪比较浮躁。当用户在浏览…

深入理解Java内存区域(最新版面试题)

1、什么是JVM&#xff1f; JVM&#xff08;Java Virtual Machine&#xff09;是用于运行Java字节码的虚拟机&#xff0c;包括一套字节码指令集、一组程序寄存器、一个虚拟机栈、一个虚拟机堆、一个方法区和一个垃圾回收器。JVM运行在操作系统之上&#xff0c;不与硬件设备直接交…