返回顶部
首页 > 资讯 > 前端开发 > VUE >如何管理JS中的内存
  • 352
分享到

如何管理JS中的内存

2024-04-02 19:04:59 352人浏览 八月长安
摘要

这篇文章主要介绍“如何管理js中的内存”,在日常操作中,相信很多人在如何管理JS中的内存问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何管理JS中的内存”的疑惑有所帮助!接

这篇文章主要介绍“如何管理js中的内存”,在日常操作中,相信很多人在如何管理JS中的内存问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何管理JS中的内存”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

JS 环境中分配的内存有如下声明周期:

  1. 内存分配:当我们申明变量、函数、对象的时候,系统会自动为他们分配内存

  2. 内存使用:即读写内存,也就是使用变量、函数等

  3. 内存回收:使用完毕,由垃圾回收机制自动回收不再使用的内存

JS 的内存分配

为了不让程序员费心分配内存,javascript 在定义变量时就完成了内存分配。

如何管理JS中的内存

有些函数调用结果是分配对象内存:

var d = new Date(); // 分配一个 Date 对象 var e = document.createElement('div'); // 分配一个 DOM 元素

有些方法分配新变量或者新对象:

var s = "azerty"; var s2 = s.substr(0, 3); // s2 是一个新的字符串 // 因为字符串是不变量, // JavaScript 可能决定不分配内存, // 只是存储了 [0-3] 的范围。 var a = ["ouais ouais", "nan nan"]; var a2 = ["generation", "nan nan"]; var a3 = a.concat(a2);  // 新数组有四个元素,是 a 连接 a2 的结果

JS 的内存使用

使用值的过程实际上是对分配内存进行读取与写入的操作。 读取与写入可能是写入一个变量或者一个对象的属性值,甚至传递函数的参数。

var a = 10; // 分配内存 console.log(a); // 对内存的使用

JS 的内存回收

JS 有自动垃圾回收机制,那么这个自动垃圾回收机制的原理是什么呢? 其实很简单,就是找出那些不再继续使用的值,然后释放其占用的内存。

大多数内存管理的问题都在这个阶段。 在这里最艰难的任务是找到不再需要使用的变量。

不再需要使用的变量也就是生命周期结束的变量,是局部变量,局部变量只在函数的执行过程中存在, 当函数运行结束,没有其他引用(闭包),那么该变量会被标记回收。

全局变量的生命周期直至浏览器卸载页面才会结束,也就是说全局变量不会被当成垃圾回收。

因为自动垃圾回收机制的存在,开发人员可以不关心也不注意内存释放的有关问题,但对无用内存的释放这件事是客观存在的。 不幸的是,即使不考虑垃圾回收对性能的影响,目前***的垃圾回收算法,也无法智能回收所有的极端情况。

接下来我们来探究一下 JS 垃圾回收的机制。

垃圾回收

引用

垃圾回收算法主要依赖于引用的概念。

在内存管理的环境中,一个对象如果有访问另一个对象的权限(隐式或者显式),叫做一个对象引用另一个对象。

例如,一个Javascript对象具有对它原型的引用(隐式引用)和对它属性的引用(显式引用)。

在这里,“对象”的概念不仅特指 JavaScript 对象,还包括函数作用域(或者全局词法作用域)。

引用计数垃圾收集

这是最初级的垃圾回收算法。

引用计数算法定义“内存不再使用”的标准很简单,就是看一个对象是否有指向它的引用。 如果没有其他对象指向它了,说明该对象已经不再需了。

如何管理JS中的内存

由上面可以看出,引用计数算法是个简单有效的算法。但它却存在一个致命的问题:循环引用。

如果两个对象相互引用,尽管他们已不再使用,垃圾回收不会进行回收,导致内存泄露。

来看一个循环引用的例子:

如何管理JS中的内存

上面我们申明了一个函数 f ,其中包含两个相互引用的对象。 在调用函数结束后,对象 o1 和 o2 实际上已离开函数范围,因此不再需要了。 但根据引用计数的原则,他们之间的相互引用依然存在,因此这部分内存不会被回收,内存泄露不可避免了。

再来看一个实际的例子:

  1. var div = document.createElement("div"); 

  2. div.onclick = function() { 

  3.  console.log("click"); 

  4. }; 
     

上面这种JS写法再普通不过了,创建一个DOM元素并绑定一个点击事件。 此时变量 div 有事件处理函数的引用,同时事件处理函数也有div的引用!(div变量可在函数内被访问)。 一个循序引用出现了,按上面所讲的算法,该部分内存无可避免的泄露了。

为了解决循环引用造成的问题,现代浏览器通过使用标记清除算法来实现垃圾回收。

标记清除算法

标记清除算法将“不再使用的对象”定义为“无法达到的对象”。 简单来说,就是从根部(在JS中就是全局对象)出发定时扫描内存中的对象。 凡是能从根部到达的对象,都是还需要使用的。 那些无法由根部出发触及到的对象被标记为不再使用,稍后进行回收。

从这个概念可以看出,无法触及的对象包含了没有引用的对象这个概念(没有任何引用的对象也是无法触及的对象)。 但反之未必成立。

工作流程:

  1. 垃圾收集器会在运行的时候会给存储在内存中的所有变量都加上标记。

  2. 从根部出发将能触及到的对象的标记清除。

  3. 那些还存在标记的变量被视为准备删除的变量。

  4. ***垃圾收集器会执行***一步内存清除的工作,销毁那些带标记的值并回收它们所占用的内存空间。

如何管理JS中的内存

循环引用不再是问题了

再看之前循环引用的例子:

function f(){  var o = {};  var o2 = {};  o.a = o2; // o 引用 o2  o2.a = o; // o2 引用 o  return "azerty"; } f();

函数调用返回之后,两个循环引用的对象在垃圾收集时从全局对象出发无法再获取他们的引用。 因此,他们将会被垃圾回收器回收。

内存泄漏

什么是内存泄漏

程序的运行需要内存。只要程序提出要求,操作系统或者运行时(runtime)就必须供给内存。

对于持续运行的服务进程(daemon),必须及时释放不再用到的内存。 否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃。

本质上讲,内存泄漏就是由于疏忽或错误造成程序未能释放那些已经不再使用的内存,造成内存的浪费。

内存泄漏的识别方法

经验法则是,如果连续五次垃圾回收之后,内存占用一次比一次大,就有内存泄漏。 这就要求实时查看内存的占用情况。

在 Chrome 浏览器中,我们可以这样查看内存占用情况

  1. 打开开发者工具,选择 PerfORMance 面板

  2. 在顶部勾选 Memory

  3. 点击左上角的 record 按钮

  4. 在页面上进行各种操作,模拟用户的使用情况

  5. 一段时间后,点击对话框的 stop 按钮,面板上就会显示这段时间的内存占用情况

来看一张效果图:

如何管理JS中的内存

我们有两种方式来判定当前是否有内存泄漏:

  1. 多次快照后,比较每次快照中内存的占用情况,如果呈上升趋势,那么可以认为存在内存泄漏

  2. 某次快照后,看当前内存占用的趋势图,如果走势不平稳,呈上升趋势,那么可以认为存在内存泄漏

服务器环境中使用 node 提供的 process.memoryUsage 方法查看内存情况

console.log(process.memoryUsage());
// { 
// rss: 27709440,
// heapTotal: 5685248,
// heapUsed: 3449392,
// external: 8772 
// }

process.memoryUsage返回一个对象,包含了 Node 进程的内存占用信息。

该对象包含四个字段,单位是字节,含义如下:

  • rss(resident set size):所有内存占用,包括指令区和堆栈。

  • heapTotal:"堆"占用的内存,包括用到的和没用到的。

  • heapUsed:用到的堆的部分。

  • external: V8 引擎内部的 c++ 对象占用的内存。

判断内存泄漏,以heapUsed字段为准。

常见的内存泄露案例

意外的全局变量

function foo() {
 bar1 = 'some text'; // 没有声明变量 实际上是全局变量 => window.bar1
 this.bar2 = 'some text' // 全局变量 => window.bar2
}
foo();

在这个例子中,意外的创建了两个全局变量 bar1 和 bar2

被遗忘的定时器和回调函数

在很多库中, 如果使用了观察者模式, 都会提供回调方法, 来调用一些回调函数。 要记得回收这些回调函数。举一个 setInterval的例子:

var serverData = loadData();
setInterval(function() {
 var renderer = document.getElementById('renderer');
 if(renderer) {
 renderer.innerhtml = JSON.stringify(serverData);
 }
}, 5000); // 每 5 秒调用一次

如果后续 renderer 元素被移除,整个定时器实际上没有任何作用。 但如果你没有回收定时器,整个定时器依然有效, 不但定时器无法被内存回收, 定时器函数中的依赖也无法回收。在这个案例中的 serverData 也无法被回收。

闭包

在 JS 开发中,我们会经常用到闭包,一个内部函数,有权访问包含其的外部函数中的变量。 下面这种情况下,闭包也会造成内存泄露:

如何管理JS中的内存

这段代码,每次调用 replaceThing 时,theThing 获得了包含一个巨大的数组和一个对于新闭包 someMethod 的对象。 同时 unused 是一个引用了 originalThing 的闭包。

这个范例的关键在于,闭包之间是共享作用域的,尽管 unused 可能一直没有被调用,但是 someMethod 可能会被调用,就会导致无法对其内存进行回收。 当这段代码被反复执行时,内存会持续增长。

DOM 引用

很多时候, 我们对 Dom 的操作, 会把 Dom 的引用保存在一个数组或者 Map 中。

如何管理JS中的内存

上述案例中,即使我们对于 image 元素进行了移除,但是仍然有对 image 元素的引用,依然无法对齐进行内存回收。

另外需要注意的一个点是,对于一个 Dom 树的叶子节点的引用。 举个例子: 如果我们引用了一个表格中的td元素,一旦在 Dom 中删除了整个表格,我们直观的觉得内存回收应该回收除了被引用的 td 外的其他元素。 但是事实上,这个 td 元素是整个表格的一个子元素,并保留对于其父元素的引用。 这就会导致对于整个表格,都无法进行内存回收。所以我们要小心处理对于 Dom 元素的引用。

如何避免内存泄漏

记住一个原则:不用的东西,及时归还。

  1. 减少不必要的全局变量,使用严格模式避免意外创建全局变量。

  2. 在你使用完数据后,及时解除引用(闭包中的变量,dom引用,定时器清除)。

  3. 组织好你的逻辑,避免死循环等造成浏览器卡顿,崩溃的问题。

到此,关于“如何管理JS中的内存”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: 如何管理JS中的内存

本文链接: https://lsjlt.com/news/79842.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 如何管理JS中的内存
    这篇文章主要介绍“如何管理JS中的内存”,在日常操作中,相信很多人在如何管理JS中的内存问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何管理JS中的内存”的疑惑有所帮助!接...
    99+
    2024-04-02
  • 分析JS中的内存管理
    这篇文章主要讲解了“分析JS中的内存管理”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“分析JS中的内存管理”吧!前言像C语言这样的底层语言一般都有底层的内存...
    99+
    2024-04-02
  • JS中内存管理的示例分析
    这篇文章将为大家详细讲解有关JS中内存管理的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。前言像C语言这样的底层语言一般都有底层的内存管理接口,比如 malloc...
    99+
    2024-04-02
  • C++ 内存管理中的内存池
    内存池是一种 c++++ 技术,用于管理频繁分配和释放的特定大小对象。它使用预分配的内存块,提供比标准内存分配器更高的性能,特别是针对高度并发的应用程序。 C++ 内存管理中的内存池 ...
    99+
    2024-05-01
    内存池 c++ 内存管理 c++
  • JS中的内存管理机制及验证方法
    这篇文章主要介绍“JS中的内存管理机制及验证方法”,在日常操作中,相信很多人在JS中的内存管理机制及验证方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”JS中的内存管理机制...
    99+
    2024-04-02
  • Linux是如何管理内存的
    这篇文章主要讲解了“Linux是如何管理内存的”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Linux是如何管理内存的”吧!基本概念每个 Linux 进程都会有地址空间,这些地址空间由三个段...
    99+
    2023-06-15
  • C++ 技术中的内存管理:如何防止内存泄漏?
    c++++ 内存管理中防止内存泄漏的最佳实践包括:1. 使用智能指针(自动释放内存);2. 正确使用 new 和 delete(成对使用,避免悬空指针);3. 使用 raii(资源超出作...
    99+
    2024-05-01
    内存泄漏 内存管理 c++ 作用域
  • C++内存管理如何理解
    这期内容当中小编将会给大家带来有关C++内存管理如何理解,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。前言;C++继承了C语言的指针,一直以来指针的一些问题困扰着开发人员,常见的指针问题主要有:内存泄露、...
    99+
    2023-06-26
  • 如何理解Linux内存管理中的RSS和VSZ
    如何理解Linux内存管理中的RSS和VSZ,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Linux内存管理中不管是top命令还是pmap命令,都会有RSS和V...
    99+
    2023-06-06
  • C++ 内存管理如何与 C 语言的内存管理进行交互?
    c++++ 内存管理与 c 语言的交互:兼容性:c++ 与 c 语言兼容,可以使用 c 中的指针和数组。指针和数组:c++ 指针和数组与 c 语言中类似,但 c++ 允许通过指针直接操纵...
    99+
    2024-05-24
    c c++
  • Aerospike的bin内存管理--即列内存管理
    1、内存申请函数调用 write_master->write_master_dim->write_master_bin_ops ->write_master_bin_ops_l...
    99+
    2024-04-02
  • C++技术中的内存管理:容器类中的内存管理技巧
    容器类中的内存管理技巧对于编写高效且可靠的 c++++ 代码至关重要,它使用栈分配、堆分配和内存池来管理数据。栈分配:临时变量和局部变量存储在函数的栈帧中,快速有效,但生命周期受函数调用...
    99+
    2024-05-07
    内存管理 容器类 c++
  • Spark中的Executor内存管理是如何进行的
    在Spark中,Executor内存管理是由Spark的内存管理器负责管理的。每个Executor会有自己的内存管理器来管理其内存,...
    99+
    2024-03-05
    Spark
  • 如何理解Linux进程的内存管理
    这篇文章给大家介绍如何理解Linux进程的内存管理,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。几个关键的数据结构一个进程的虚拟地址空间主要由两个数据结来描述,一个是 mm_struct,一个是 vm_area_str...
    99+
    2023-06-15
  • 如何理解Java代码的内存管理
    这期内容当中小编将会给大家带来有关如何理解Java代码的内存管理,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。小编通过几个方面来介绍Java代码的内存管理。有的代码,GC根本就回收不了,直接系统挂掉。GC...
    99+
    2023-06-17
  • 如何进行C++内存管理?
    如何进行C++内存管理C++是一种强大的编程语言,但是它也要求开发者负责内存管理。在C++中,内存管理是非常重要的,因为错误的内存使用可能导致内存泄漏、野指针和其他一系列问题。因此,对于C++开发者来说,掌握良好的内存管理技巧至关重要。C+...
    99+
    2023-11-02
    内存分配 (Allocation) 内存释放 (Deallocation) 智能指针 (Smart Pointers)
  • C++技术中的内存管理:如何优化内存分配策略?
    优化 c++++ 内存分配策略至关重要,包括选择合适的分配器(new/delete、std::allocator、第三方分配器)和分配策略(堆分配、栈分配、对象池、slab 分配器)。通...
    99+
    2024-05-07
    c++ 内存管理 作用域 标准库
  • PHP 函数中如何管理内存占用?
    php函数中管理内存占用需:避免声明不必要的变量;使用轻量级数据结构;释放未使用的变量;优化字符串处理;限制函数参数;优化循环和条件,例如避免死循环和使用索引数组。 PHP 函数中管理...
    99+
    2024-04-26
    php 内存管理 内存占用
  • 如何处理PHP开发中的文件缓存和内存管理
    在PHP开发中,文件缓存和内存管理是两个非常重要的方面。良好的文件缓存和内存管理可以显著提升应用的性能和可靠性。本文将介绍如何在PHP中进行文件缓存和内存管理,并给出具体的代码示例。一、文件缓存文件缓存是将已经生成的内容保存在文件中,下次访...
    99+
    2023-10-21
    内存管理 PHP开发 文件缓存
  • 详解android是如何管理内存的
    目录前言Java Heap进程内存分配内存不足管理GC 垃圾回收内核交换守护进程低内存终止守护进程最后前言 很高兴遇见你~ 内存优化一直是 Android 开发中的一个非常重要的话...
    99+
    2024-04-02
软考高级职称资格查询
推荐阅读
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作