常见的内存泄漏及其避免方法(一)

挑战更文更新面试题系列,趁着更文活动把一些常见的面试题进行一下整理,本次文章更新的是对内存泄露的一些针对的问题

什么是内存泄露

内存泄漏是指程序中已分配的内存(通常是堆内存)无法被垃圾回收器正常释放,导致程序持续占用内存,最终可能导致应用程序性能下降或崩溃。内存泄漏通常是开发中的一个常见问题,尤其在长时间运行的应用程序中。

在日常的项目开发中内存泄露是一个比较容易被大家忽略的问题,但在面试中确是一个常考的内容,下面是几个比较常见的场景。

未释放资源

如果程序使用了像文件句柄、网络连接、数据库连接等资源,但在使用完后未正确关闭或释放它们,就会导致资源泄漏。我们应该确保在不再需要资源时进行适当的关闭和释放。这是一个比较大的概念,可以说是概况了下面的大部分内容。

未关闭文件或流比如下面这段代码,对于在node中使用文件流,应当用完及时关闭,确保在不再需要时使用 close() 方法关闭文件流,或使用 try...finally 块来确保资源释放。

ini 复制代码
javascriptCopy code
const fs = require('fs');
const fileStream = fs.createReadStream('example.txt');

// fileStream.close(); 

未释放数据库连接也是同样的道理,无论是哪种链接,都应该在用完之后回收。在不再需要数据库连接时,使用库提供的方法(如 close)关闭连接,或使用连接池来管理连接,可以有效的减少内存泄露。

ini 复制代码
javascriptCopy code
const db = require('database-library');
const connection = db.connect('db-url');

// 如果忘记关闭数据库连接,它将一直保持连接状态
// db.close(connection); // 应当关闭数据库连接

未释放网络连接也是同样的概念,在服务不需要时,使用 close() 方法来关闭服务器。

ini 复制代码
javascriptCopy code
const http = require('http');
const server = http.createServer((req, res) => {
  // 处理请求
});

server.listen(3000);

// 如果忘记关闭服务器,它将一直监听端口
// server.close(); // 应当关闭服务器

循环引用

在某些情况下,对象之间的相互引用可能会导致内存泄漏。垃圾回收器无法清除已不再使用的对象,因为它们仍然被其他对象引用。确保在不再需要时解除对象之间的循环引用。

比如下面这个列子中obj1 和 obj2 形成了循环引用,导致它们不会被垃圾回收,因为两者之间存在相互的一个引用,互相依赖,所以被认为都是不可被回收的一个变量,进一步导致了占用内存,内存泄露就发生了。

js 复制代码
// 循环引用示例
function createCircularReference() {
  const obj1 = {};
  const obj2 = {};
  obj1.ref = obj2;
  obj2.ref = obj1;
  // obj1 和 obj2 形成了循环引用,导致它们不会被垃圾回收
}
createCircularReference();

事件监听器未移除

使用事件监听器,但在组件卸载或不再需要时未移除它们,就会导致内存泄漏。在不再需要监听器时,确保移除它们。

平时的开发中我们经常会到一些事件的监听,记得刚开始写监听事件的时候总是会忽略对事件的一些卸载,如果忘记卸载的话,是很容易导致内存泄露的一个点,尤其是当监听事件比较多的时候。比如下面使用了addEventListener来增加监听,需要用到removeEventListener来移除

javascript 复制代码
javascriptCopy code
// 未清除事件监听器示例
const button = document.getElementById('myButton');
button.addEventListener('click', function () {
  // 事件处理程序逻辑
});

// 如果忘记移除事件监听器,将导致内存泄漏
// button.removeEventListener('click', eventHandler); // 应当移除监听器

解决方法:在不再需要事件监听器时,使用 removeEventListener 来移除它们。

定时器未清除

定时器(例如 setTimeoutsetInterval)也可能导致内存泄漏。确保在不再需要定时器时使用 clearTimeoutclearInterval 清除它们。

定时器和监听器也是同样的概念,如果计时器和监听器没有被清除,那么和监听器一样都会在后台不听的进行更新和循环,这同样是一个导致内存泄露的问题。

javascript 复制代码
javascriptCopy code
// 未清除定时器示例
const timerId = setTimeout(function () {
  // 定时器逻辑
}, 1000);

// 如果忘记清除定时器,它将一直运行,阻止函数被垃圾回收
// clearTimeout(timerId); // 应当清除定时器

解决方法:使用 clearTimeoutclearInterval 来清除不再需要的定时器。

🙏 感谢您花时间阅读这篇文章!如果觉得有趣或有收获,请关注我的更新,给个喜欢和分享。您的支持是我写作的最大动力!

往期好文推荐

相关推荐
涡能增压发动积11 小时前
同样的代码循环 10次正常 循环 100次就抛异常?自定义 Comparator 的 bug 让我丢尽颜面
后端
Wenweno0o11 小时前
0基础Go语言Eino框架智能体实战-chatModel
开发语言·后端·golang
于慨11 小时前
Lambda 表达式、方法引用(Method Reference)语法
java·前端·servlet
石小石Orz11 小时前
油猴脚本实现生产环境加载本地qiankun子应用
前端·架构
swg32132111 小时前
Spring Boot 3.X Oauth2 认证服务与资源服务
java·spring boot·后端
从前慢丶11 小时前
前端交互规范(Web 端)
前端
tyung11 小时前
一个 main.go 搞定协作白板:你画一笔,全世界都看见
后端·go
gelald11 小时前
SpringBoot - 自动配置原理
java·spring boot·后端
CHU72903512 小时前
便捷约玩,沉浸推理:线上剧本杀APP功能版块设计详解
前端·小程序
GISer_Jing12 小时前
Page-agent MCP结构
前端·人工智能