优化 Node.js 性能:检测内存泄漏和高 CPU 使用率

优化 Node.js 性能:检测内存泄漏和高 CPU 使用率

Node.js 是一种流行的 JavaScript 运行时,以其速度、性能和可扩展性而闻名。然而,即使是优化和编写得非常好的 Node.js 应用程序也可能会遇到性能问题,例如内存泄漏和 CPU 使用率过高。分析是帮助识别和解决这些性能瓶颈的关键过程。在本教程中,我们将介绍用于分析 Node.js 应用程序的最佳实践和工具,包括如何检测内存泄漏和高 CPU 使用率。

分析的重要性

分析 Node.js 很重要,它可以帮助我们了解应用程序如何使用 CPU、内存和 I/O 等资源并识别性能瓶颈。分析可以提供有价值的信息,可用于优化应用程序、减少完成任务所需的时间、减少内存使用并提高整体响应能力。

  • 优化性能 - 分析有助于识别应用程序中的性能瓶颈,例如响应时间慢和 CPU 使用率高。通过解决这些瓶颈,我们可以提高应用程序的整体性能。
  • 提高稳定性 - 分析可帮助我们识别应用程序中的稳定性问题,例如内存泄漏。通过解决这些问题,我们可以提高应用程序的整体稳定性。
  • 节省资源 - 分析可帮助我们识别应用程序中的资源使用情况,例如内存和 CPU 使用情况。通过减少资源使用,我们可以节省成本并提高应用程序的可扩展性。

可使用的工具

Chrome 开发工具

Chrome DevTools 是一款功能强大的 Node.js 应用程序调试和分析工具。它们提供有关应用程序的大量信息,包括内存使用情况、CPU 使用情况、请求计数、响应时间等。要访问 Chrome DevTools,可以通过在终端中键入node --inspect命令来使用命令行界面。

Node Inspector

Node InspectorNode.js 应用程序的强大调试和分析工具。它提供了一个图形用户界面,可以轻松监控我们的应用程序,包括内存使用情况、CPU 使用情况、请求计数、响应时间等。要使用 Node Inspector,可以通过在终端中键入npm install -g node-inspector命令安装。

node-memwatch

node-memwatch是一个 Node.js 模块,可帮助跟踪 Node.js 应用程序中的内存使用情况并检测内存泄漏。它提供了一个API来监视堆大小、堆使用情况和堆中对象的数量,以及跟踪GC(垃圾收集)统计信息。它还提供了用于检测内存泄漏和生成堆快照的工具,可用于识别内存问题的原因。

memwatch.on('leak', function(info) { ... });

v8-profiler

v8-profiler是一个用于分析 Node.js 应用程序的 npm 库。它提供了一个 API,用于使用 V8 JavaScript 引擎的内置分析器来分析 Node.js 运行时中运行的 JavaScript 代码。探查器收集有关 JavaScript 代码执行的信息,例如函数调用计数、函数计时和内存使用情况,可以分析这些信息以识别应用程序中的性能瓶颈和内存泄漏。

该库允许我们启动和停止分析会话、拍摄堆和分析数据的快照,并以人类可读的格式生成分析数据的报告。配置文件数据还可以保存到文件中并加载到可视化工具中以进行进一步分析。

const express = require('express');
const v8Profiler = require('v8-profiler');
const path = require('path');
const fs = require('fs');const app = express();
const snapshots = new Map();// 用于获取堆快照
app.get('/api/heap-snapshot', (req, res) => {const snapshot = v8Profiler.takeSnapshot();const name = snapshot.getHeader().title;snapshots.set(name, snapshot);res.send({ name });
});// 用于按名称下载堆快照
app.get('/api/heap-snapshot/:name', (req, res) => {const name = req.params.name;const snapshot = snapshots.get(name);if (!snapshot) {return res.status(404).send({ error: 'Snapshot not found' });}const fileName = `${name}.heapsnapshot`;const filePath = path.resolve(__dirname, 'snapshots', fileName);snapshot.serialize({ write: chunk => fs.appendFileSync(filePath, chunk) },() => {res.download(filePath, fileName, error => {if (error) {console.error(error);}snapshots.delete(name);});});
});const port = process.env.PORT || 3000;
app.listen(port, () => {console.log(`Server listening on port ${port}`);
});

示例

内存泄漏

以下代码创建一个简单的 HTTP 服务器。

const express = require("express");
const app = express();
let data = [];app.get("/leak", (req, res) => {setInterval(() => {data.push(new Array(1000000).join("a"));}, 1000);res.send("Memory leak started!");
});app.listen(3000, () => {console.log("Server started on port 3000");
});

setInterval函数创建一个包含大量数据的新数组,并每秒将其推送到data数组。问题在于数据永远不会从内存中释放,导致内存使用量持续增加,称为内存泄漏。随着时间的推移,应用程序的内存使用量将会增加,直到最终由于内存不足而崩溃。要修复此内存泄漏,我们需要从内存中删除未使用的数据,例如,通过设置data = []来处理不需要的数据。

要检测内存泄漏,我们可以通过在终端中键入node --inspect命令来使用 Chrome DevToolsChrome DevTools 打开后,我们可以导航到“memory”选项卡并选择Take Heap Snapshot。这将为我们提供内存使用情况的快照。然后,我们可以将此快照与以后的快照进行比较,看看内存使用量是否随着时间的推移而增加。

目的是比较在不同时间点拍摄的两个堆快照,以查看哪些对象在内存中累积。这使我们可以查看哪些对象没有被垃圾收集,并确定是否发生内存泄漏。

在这里插入图片描述

重要的是比较不同时间点拍摄的堆快照以确定是否发生内存泄漏。比较堆快照时,我们除了查找快照之间大小或数量增加的对象外,还应该查看每个对象的参考图,以确定它没有被垃圾收集的原因。在许多情况下,对象之间的循环引用可能会导致内存泄漏,因为对象无法被垃圾收集,因为它们仍然被其他对象引用。

  • Shallow size:这是内存中对象的大小,包括其属性占用的内存以及存储在这些属性中的任何值的大小。
  • Retained size:这是如果对象被垃圾回收将释放的总内存,不仅包括对象本身的浅层大小,还包括该对象引用的所有对象的浅层大小,即使它们不是直接引用的代码的其他部分。

换句话说,对象的保留大小是其浅层大小与所有因该对象引用而无法被垃圾收集的对象的浅层大小之和。此测量可以帮助我们识别占用大量内存的对象,即使它们本身没有很大的浅层大小。

CPU 使用率高

const express = require("express");
const app = express();
function highCPUFunction() {let sum = 0;for (let i = 0; i < 10000000; i++) {sum += Math.pow(Math.sin(i), i);}return sum;
}
app.get("/high-cpu", (req, res) => {const start = Date.now();// 执行计算密集型操作const result = highCPUFunction();const end = Date.now();console.log(`Computation took ${end - start}ms`);res.send(result);
});
app.listen(3000, () => {console.log("Server started on port 3000");
});

上面的代码创建了一个highCPUFunction函数,该函数执行 10M 次迭代的循环。计算完成循环所需的时间并将其记录到控制台。

这种计算密集型操作可能会导致 CPU 使用率较高,因为 CPU 将努力执行循环中的计算。CPU 使用量取决于 CPU 的处理能力和可用系统资源等因素。

导航到Performance选项卡并选择Start profiling,一旦开始分析,我们就可以访问http://localhost:3000/high-cpu,这将开始对应用程序进行分析,并为我们提供 CPU 使用情况的详细视图,包括哪些函数使用最多的 CPU 时间。
在这里插入图片描述

结论

分析是优化 Node.js 应用程序性能、稳定性和可扩展性的重要过程。通过使用 Node.js 内置进程管理器、Chrome DevToolsNode Inspector 等工具,我们可以轻松监控和解决内存泄漏、CPU 使用率过高等性能问题。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

yolov8 opencv模型部署(C++版)

yolov8 opencv模型部署&#xff08;C 版&#xff09; 使用opencv推理yolov8模型&#xff0c;仅依赖opencv&#xff0c;无需其他库&#xff0c;以yolov8s为例子&#xff0c;注意&#xff1a; 使用opencv4.8.0 &#xff01;使用opencv4.8.0 &#xff01;使用opencv4.8.0 &#…

Python函数语法与面向对象回顾(精华)

目录 函数 语法定义 返回值 位置参数 关键字传递 默认参数 函数参数中 / 作用 lambda表达式 递归函数 面向对象 初识对象 继承 构造函数 ​编辑 多态 "私有属性" 动态 类方法和静态方法 函数 语法定义 pyhon的函数定义语法是 def 函数名(参数…

基于SpringBoot的师生共评的作业管理系统设计与实现

目录 前言 一、技术栈 二、系统功能介绍 课程管理 作业管理 作业互评 小组管理 作业管理 作业评分 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 随着信息互联网信息的飞速发展&#xff0c;无纸化作业变成了一种趋势&#xff0c;针对这个问题开发一个…

蓝桥等考Python组别十级003

第一部分&#xff1a;选择题 1、Python L10 &#xff08;15分&#xff09; 已知s Pencil&#xff0c;下列说法正确的是&#xff08; &#xff09;。 s[0]对应的字符是Ps[1]对应的字符是ns[-1]对应的字符是is[3]对应的字符是e 正确答案&#xff1a;A 2、Python L10 &am…

【GDB】 command 命令

GDB command 命令 语法 command 命令是一个很好用的调试命令&#xff0c;它配合断点使用&#xff0c;可以在指定的断点执行预先设置的命令 其语法为&#xff1a;command bread_id&#xff0c;这样会提示你输入你要执行的命令&#xff0c;以 end 结束。这个 bread_id 就是用 …

【Axure】Axure的常用功能

选择 分为相交选中和包含选中 相交选中&#xff1a;部分选中即是选中包含选中&#xff1a;全选才是选中 缩放 按住元件四角&#xff0c;等比例缩放 置顶和置底 所谓置于顶层就是不被后来的元件覆盖住&#xff0c;置于底层的意思则相反 组合、对齐、分布 组合&#xff1…

Java安全之servlet内存马分析

目录 前言 什么是中间键 了解jsp的本质 理解servlet运行机制 servlet的生命周期 Tomcat总体架构 查看Context 的源码 servlet内存马实现 参考 前言 php和jsp一句话马我想大家都知道&#xff0c;早先就听小伙伴说过一句话木马已经过时了&#xff0c;现在是内存马的天下…

Spring MVC 十:异常处理

异常是每一个应用必须要处理的问题。 Spring MVC项目&#xff0c;如果不做任何的异常处理的话&#xff0c;发生异常后&#xff0c;异常堆栈信息会直接抛出到页面。 比如&#xff0c;我们在Controller写一个异常&#xff1a; GetMapping(value"/hello",produces{&qu…

搭建前端框架

在终端进入web目录&#xff0c;然后创建vuecrud工程 创建工程并引入ElementUI和axios手把手教学>传送门:VueCLI脚手架搭建

2023.09.30使用golang1.18编译Hel10-Web/Databasetools的windows版

#Go 1.21新增的 log/slog 完美解决了以上问题&#xff0c;并且带来了很多其他很实用的特性。 本次编译不使用log/slog 包 su - echo $GOPATH ;echo $GOROOT; cd /tmp; busybox wget --no-check-certificate https://go.dev/dl/go1.18.linux-amd64.tar.gz;\ which tar&&am…

驱动插入中断门示例代码

驱动插入中断描述符示例代码 最近做实验&#xff0c;每次在应用层代码写测试代码的时候都要手动挂一个中断描述符&#xff0c;很不方便所以就想着写个驱动挂一个中断门比较省事 驱动测试效果如下&#xff1a; 下面的代码是个架子&#xff0c;用的时候找个驱动历程传递你要插…

搭建智能桥梁,Amazon CodeWhisperer助您轻松编程

零&#xff1a;前言 随着时间的推移&#xff0c;人工智能技术以惊人的速度向前发展&#xff0c;正掀起着全新的编程范式革命。不仅仅局限于代码生成&#xff0c;智能编程助手等创新应用也进一步提升了开发效率和代码质量&#xff0c;极大地推动着软件开发领域的快速繁荣。 当前…

小白继续深入学习C++

第1节 指针的基本概念 1、变量的地址&#xff1a; 变量是内存地址的简称&#xff0c;在C中&#xff0c;每定义一个变量&#xff0c;系统就会给变量分配一块内存&#xff0c;内存是有地址的。 C用运算符&获取变量在内存中的起始地址。 语法&#xff1a; &变…

如果在 Mac 上的 Safari 浏览器中无法打开网站

使用网络管理员提供的信息更改代理设置。个人建议DNS解析&#xff0c;设置多个例如114.114.114.114 8.8.8.8 8.8.4.4 如果打不开网站&#xff0c;请尝试这些建议。 在 Mac 上的 Safari 浏览器 App 中&#xff0c;检查页面无法打开时出现的信息。 这可能会建议解决问题的…

Chrome(谷歌浏览器)如何关闭搜索栏历史记录

目录 问题描述解决方法插件解决&#xff08;亲测有效&#xff09;自带设置解决步骤首先打开 地址 输入&#xff1a;chrome://flags关闭浏览器&#xff0c;重新打开Chrome 发现 已经正常 问题描述 Chrome是大家熟知的浏览器&#xff0c;但是搜索栏的历史记录如何自己一条条的删…

第80步 时间序列建模实战:GRNN回归建模

基于WIN10的64位系统演示 一、写在前面 这一期&#xff0c;我们使用Matlab进行GRNN模型的构建。 使用的数据如下&#xff1a; 采用《PLoS One》2015年一篇题目为《Comparison of Two Hybrid Models for Forecasting the Incidence of Hemorrhagic Fever with Renal Syndrom…

(高阶) Redis 7 第16讲 预热/雪崩/击穿/穿透 缓存篇

面试题 什么是缓存预热/雪崩/击穿/穿透如何做缓存预热如何避免或减少缓存雪崩穿透和击穿的区别?穿透和击穿的解决方案出现缓存不一致时,有哪些修补方案缓存预热 理论 将需要的数据提前加载到缓存中,不需要用户使用的过程中进行数据回写。(比如秒杀活动数据等) 方案 1.…

软件设计师_操作系统基本原理_学习笔记

文章目录 2.1 操作系统概述2.2 进程2.2.1 进程状态转换图2.2.2 前趋图2.2.3 进程的同步与互斥2.2.4 PV操作2.2.5 死锁 2.3 存储管理2.3.1 分区存储管理 2.1 操作系统概述 2.2 进程 2.2.1 进程状态转换图 2.2.2 前趋图 哪些任务可以并行&#xff0c;哪些任务有先后关系&#xf…

设计一个简单的通讯录

目录 导读&#xff1a; 一、主函数 1. 打印功能菜单 2. 用枚举常量列举功能给功能赋值&#xff08;0-5&#xff09; 3. main主函数 二、头文件 三、通讯录各功能的实现 1. 初始化通讯录 2. 增加联系人 3. 展示所有联系人信息 4. 删除指定联系人 5. 查询指定联系人…

elasticsearch+logstash+kibana整合(ELK的使用)第一课

一、安装elasticsearch 0、创建目录&#xff0c;统一放到/data/service/elk 1、下载安装包 wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.1.0-linux-x86_64.tar.gz2、解压 tar -xzvf elasticsearch-7.1.0-linux-x86_64.tar.gz3、新建用户和组…