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

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

什么是内存泄露

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

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

未释放资源

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

未关闭文件或流比如下面这段代码,对于在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 来清除不再需要的定时器。

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

往期好文推荐

相关推荐
LYFlied5 分钟前
【算法解题模板】-【回溯】----“试错式”问题解决利器
前端·数据结构·算法·leetcode·面试·职场和发展
composurext6 分钟前
录音切片上传
前端·javascript·css
我命由我123456 分钟前
Python Flask 开发:在 Flask 中返回字符串时,浏览器将其作为 HTML 解析
服务器·开发语言·后端·python·flask·html·学习方法
程序员小寒6 分钟前
前端高频面试题:深拷贝和浅拷贝的区别?
前端·javascript·面试
狮子座的男孩11 分钟前
html+css基础:07、css2的复合选择器_伪类选择器(概念、动态伪类、结构伪类(核心)、否定伪类、UI伪类、目标伪类、语言伪类)及伪元素选择器
前端·css·经验分享·html·伪类选择器·伪元素选择器·结构伪类
zhougl99612 分钟前
Vue 中的 `render` 函数
前端·javascript·vue.js
听风吟丶13 分钟前
Spring Boot 自动配置深度解析:原理、实战与源码追踪
前端·bootstrap·html
跟着珅聪学java14 分钟前
HTML中设置<select>下拉框默认值的详细教程
开发语言·前端·javascript
IT_陈寒14 分钟前
JavaScript 性能优化:5个被低估的V8引擎技巧让你的代码提速50%
前端·人工智能·后端
想睡好21 分钟前
setup
前端·javascript·html