检测Web浏览器上的内存泄漏

目录

背景

拍摄堆快照

一个真实世界的例子——AsyncSubject

附加说明

兴趣点


背景

当您关闭浏览器选项卡时,所有内存都将被释放。内存泄漏在Web浏览器上很可能不是大问题。但是如果你有一个长时间运行的应用程序,它可能是一个问题。这是关于如何检测Web浏览器上的内存泄漏的说明。在本说明中,我将使用示例来展示如何在开发工具上使用内存功能。我注意到ChromeEdge上的开发工具是最容易使用的。

拍摄堆快照

ChromeEdge开发工具中,我们可以采用三种内存配置文件。

在这篇笔记中,我将重点关注堆快照,它非常有效地精确定位导致内存泄漏的对象。测试HTML页面如下:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
    
<style>
    
    button {
        height: 60px;
        border-radius: 5px;
        font-weight: 800;
        background-color: aquamarine;
    }
    
</style>
<title>Memory test - first attempt</title>
    
<script>
let MTestClassesArray = [];
    
class MTestClass {
    constructor() {}
}
    
const create_1000_objects = () => {
    for(let i = 0; i < 1000; i++) {
        MTestClassesArray.push(new MTestClass());
    }
    
    const text = `Total ${MTestClassesArray.length} `
        + `MTestClass objects created`;
    document.getElementById('divMsg').innerHTML = text;
};
    
</script>
    
</head>
    
<body>
    <button onclick="create_1000_objects()">
        Create 1000 MTestClass objects
    </button>
    <div id="divMsg" />
</body>
</html>

  • 在这个HTML页面中,我们有一个按钮。
  • 每次单击按钮,都会创建1000MTestClass类型的对象。
  • 每个对象都插入到数组“ MTestClassesArray中。
  • 由于数组MTestClassesArray是在全局范围内声明的,因此对象不再是可垃圾回收的。

为了验证上述陈述,让我们加载页面并单击几次按钮。在我的实验中,我使用了Edge

正如页面中所示,我已单击该按钮3次,并创建了3000 MTestClass对象。我们可以通过CTRL+SHIFT+i调出开发工具。在获取内存快照之前,让我们首先强制进行垃圾回收。

然后我们可以在垃圾收集之后拍摄内存快照。

内存快照使我们能够很好地了解内存堆。

  • 我们可以过滤快照以检查某些类类型的对象是否在内存堆中。在我们的示例中,我们可以看到正好3000“ MTestClass对象。
  • 我们还可以看到是什么对象阻止了“ MTestClass对象被垃圾收集。在我们的示例中,它是MTestClassesArray对象。

开发工具甚至可以告诉我们哪一行代码创建了MTestClass对象。

一个真实世界的例子——AsyncSubject

如果您订阅了一个事件,则需要取消订阅它。如果没有,很可能是内存泄漏。但是rxjs中 "AsyncSubject"是这样吗?

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
    
<style>
    
    button {
        height: 60px;
        border-radius: 5px;
        font-weight: 800;
        background-color: aquamarine;
    }
    
</style>
<title>Memory test - async subject</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/7.1.0/rxjs.umd.js"></script>
    
<script>
const get_time = () => {
    const element = document.getElementById('divTime');
    const subject = new rxjs.AsyncSubject();
    
    element.innerHTML = '';
    
    setTimeout(() => {
        subject.next(new Date());
        subject.complete();
    
    }, 3 * 1000);
    
    subject.subscribe((data) => {
        element.innerHTML = data.toString();
    });
};    
    
</script>
</head>
    
<body>
    <button onclick="get_time()">Get Time by AsyncSubject</button>
    <div id="divTime"></div>
</body>
</html>

  • 在这个HTML页面中,我们有一个按钮。
  • 点击按钮,页面上会显示当前时间。
  • 我没有直接获取时间,而是创建了一个AsyncSubject,时间是在定时器回调函数中获取的。
  • 然后程序订阅AsyncSubject并将其显示在页面上。

需要注意的是,AsyncSubject是在get_time箭头函数中创建的,因此与任何全局上下文无关。我将假设它在计时器回调之后是可垃圾回收的。但是让我们确认它正在使用开发工具。

单击按钮和显示时间之间有3秒的延迟。为了确认AsyncSubject是可垃圾回收的,让我们拍两个堆快照。一个在定时器回调之前,一个在定时器回调之后。

在定时器回调之前,我们可以在内存堆中找到AsyncSubject。此时,它不是垃圾回收的,因为它被一些其他资源保留并且最终可以从window对象访问。

但是在定时器回调之后,AsyncSubject收集了“ ”。如果没有收集,您可以手动强制收集。通过这个例子,我们可以对我们的程序更有信心。如果“ AsyncSubject使用正确,我们不需要取消订阅该事件。

附加说明

  • 已经注意到,如果你曾经console.log()一个对象,它就不再是可垃圾回收的。在生产版本中,如果您有内存问题,您应该记住这一点。
  • 在堆快照中搜索对象时,如果您的程序被缩小,则可以通过缩小器更改类的名称。

兴趣点

  • 这是关于如何检测Web浏览器上的内存泄漏的说明。
  • 开发工具对于我们了解内存堆非常有用。
  • 我希望你喜欢我的文章,我希望这篇笔记能以一种或另一种方式帮助你。

Detect Memory Leak on Web Browsers - CodeProject

Guess you like

Origin blog.csdn.net/mzl87/article/details/121098435