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

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

什么是内存泄露

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

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

未释放资源

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

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

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

往期好文推荐

相关推荐
熊的猫4 分钟前
webpack 核心模块 — loader & plugins
前端·javascript·chrome·webpack·前端框架·node.js·ecmascript
速盾cdn11 分钟前
速盾:vue的cdn是干嘛的?
服务器·前端·网络
hlsd#41 分钟前
go mod 依赖管理
开发语言·后端·golang
四喜花露水44 分钟前
Vue 自定义icon组件封装SVG图标
前端·javascript·vue.js
陈大爷(有低保)1 小时前
三层架构和MVC以及它们的融合
后端·mvc
亦世凡华、1 小时前
【启程Golang之旅】从零开始构建可扩展的微服务架构
开发语言·经验分享·后端·golang
河西石头1 小时前
一步一步从asp.net core mvc中访问asp.net core WebApi
后端·asp.net·mvc·.net core访问api·httpclient的使用
前端Hardy1 小时前
HTML&CSS: 实现可爱的冰墩墩
前端·javascript·css·html·css3
2401_857439691 小时前
SpringBoot框架在资产管理中的应用
java·spring boot·后端
怀旧6661 小时前
spring boot 项目配置https服务
java·spring boot·后端·学习·个人开发·1024程序员节