汇总:JavaScript垃圾收集机制
优采云 发布时间: 2022-11-17 19:35汇总:JavaScript垃圾收集机制
JavaScript 具有自动垃圾采集功能,即执行环境负责管理代码执行期间使用的内存。在 C 和 C++ 等语言中,开发人员的一项基本任务是手动跟踪内存使用情况,这是许多问题的根源。在编写 JavaScript 程序时,开发者无需再关心内存使用问题,所需内存的分配和无用内存的回收完全自动管理。这种垃圾回收机制的原理其实很简单:找出不再使用的变量,然后释放它们占用的内存。为此,垃圾采集器会定期(或在代码执行期间的预定采集时间)定期执行此操作。
我们来分析一下函数中局部变量的正常生命周期。局部变量仅在函数执行期间存在。在这个过程中,会在栈(或堆)内存上为局部变量分配相应的空间,用于存放它们的值。这些变量然后在函数中使用,直到函数执行结束。此时,局部变量已经没有存在的必要了,所以它们的内存可以释放出来以备后用。在这种情况下,很容易判断该变量是否仍然是必要的;但要在所有情况下得出结论并不是那么容易。垃圾采集器必须跟踪哪些变量有用,哪些变量没用,并标记不再有用的变量,以便将来回收它们占用的内存。
4.3.1 标记去除
JavaScript 中最常见的垃圾回收形式是标记清除。当一个变量进入环境时(例如,在函数中声明一个变量),它被标记为“进入环境”。从逻辑上讲,进入环境的变量占用的内存永远不会被释放,因为只要执行流进入相应的环境,它们就可能被使用。当变量离开环境时,它被标记为“离开环境”。
变量可以用任何方式标记。例如,您可以通过翻转特殊状态来记录变量何时进入环境,或者使用“进入环境”的变量列表和“脱离环境”的变量列表来跟踪哪个变量发生了变化。归根结底,如何标注变量并不重要,关键在于采用的策略。
垃圾采集器在运行时会标记所有存储在内存中的变量(当然你可以使用任何标记方法)。然后它剥离环境中的变量和环境中变量引用的变量。之后被标记的变量将被视为要删除的变量,因为环境中的变量无法再访问这些变量。最后,垃圾回收器完成内存清理,销毁那些标记的值,回收它们占用的内存空间。
截至 2008 年,IE、Firefox、Opera、Chrome 和 Safari 的 JavaScript 实现都使用标记清除垃圾采集策略(或类似的东西),但间隔不同。
4.3.2 引用计数
另一种不太常见的垃圾采集策略称为引用计数。引用计数的意义是记录每个值被引用的次数。当一个变量被声明并且引用类型的值赋给该变量时,引用次数为1。如果相同的值赋给另一个变量,则该值的引用计数加1。反之,如果该变量收录对该值的引用取另一个值,该值减1。当对该值的引用数变为0时,意味着没有办法访问该值,因此可以回收其占用的内存空间。这样,下次垃圾采集器运行时,它将释放那些零引用值占用的内存。
Netscape Navigator 3.0 是第一个使用引用计数策略的浏览器,但很快就遇到了一个严重的问题:循环引用。循环引用意味着对象 A 收录指向对象 B 的指针,对象 B 也收录对对象 A 的引用。考虑以下示例:
函数问题(){
var objectA = new Object();
var objectB = new Object();
objectA.someOtherObject = objectB;
对象 B. 另一个对象=对象A;
}
在此示例中,objectA 和 objectB 通过各自的属性相互引用;也就是说,两个对象的引用计数都是 2。在标记清除实现中,这种交叉引用不是问题,因为两个对象在函数执行后都超出了作用域。但是在使用引用计数策略的实现中,当函数执行时,objectA和objectB会继续存在,因为它们的引用计数永远不会为0。如果重复调用这个函数,大量的内存将得不到回收。为此,Netscape 放弃了 Navigator 4.0 中的引用计数方式,转而采用标记清扫的方式来实现其垃圾回收机制。然而,引用计数带来的麻烦并没有就此结束。
我们知道 IE 中的一些对象并不是原生的 JavaScript 对象。例如,其BOM和DOM中的对象使用C++以COM(Component Object Model,组件对象模型)对象的形式实现,COM对象的垃圾回收机制采用引用计数策略。因此,即使IE的JavaScript引擎是使用标记清除策略实现的,JavaScript访问的COM对象仍然是基于引用计数策略的。也就是说,只要在IE中涉及到COM对象,就会出现循环引用的问题。下面是一个简单的示例,演示了使用 COM 对象时的循环引用问题:
var 元素 = 文档。getElementById("some_element");
var myObject = new Object();
我的对象。元素=元素;
element.someObject = myObject;
此示例在 DOM 元素 (element) 和原生 JavaScript 对象 (myObject) 之间创建循环引用。其中,变量myObject有一个名为element的属性,指向元素对象;并且变量元素还有一个名为 someObject 的属性,它引用回 myObject。因为这个循环引用,即使示例中的 DOM 从页面中移除,它也永远不会被回收。
为避免此类循环引用问题,最好在不使用原生 JavaScript 对象时手动断开它们与 DOM 元素的连接。例如,可以使用以下代码消除上一个示例创建的循环引用:
我的对象。元素=空;
element.someObject = null;
将变量设置为 null 意味着切断变量与其先前引用的值之间的连接。下次垃圾采集器运行时,这些值会被移除,它们占用的内存也会被回收。
为了解决上述问题,IE9将BOM和DOM对象都转换为真正的JavaScript对象。这样就避免了两种垃圾回收算法并存带来的问题,也消除了常见的内存泄露问题。
这些并不是导致循环引用的唯一情况,其他情况将在本书中介绍。
4.3.3 性能问题
垃圾采集器定期运行,如果为变量分配的内存量很大,则采集工作量可能很大。在这种情况下,确定垃圾回收的时间间隔是一个非常重要的问题。说到垃圾采集器的运行频率,不禁会想到IE臭名昭著的性能问题。IE 的垃圾采集器在内存分配上运行,特别是 256 个变量、4096 个对象(或数组)文字和数组元素(槽)或 64KB 字符串。当达到上述任何阈值时,垃圾采集器将运行。此实现的问题在于,如果脚本中有那么多变量,脚本很可能会在其整个生命周期内保留那么多变量。而且这样一来,垃圾采集器就得经常运行。
随着 IE7 的发布,JavaScript 引擎的垃圾采集例程改变了它们的工作方式:触发垃圾采集的变量分配、文字和/或数组元素的阈值被调整为动态更正。IE7中的阈值最初与IE6中的阈值相等。如果垃圾采集例程回收的分配少于 15%,则变量、文字和/或数组元素的阈值加倍。如果例程回收了其内存分配的 85%,则将各种阈值重置为默认值。这个看似简单的调整极大地提高了 IE 在运行收录大量 JavaScript 的页面时的性能。
事实上,在某些浏览器中是可以触发垃圾回收过程的,但我们不建议读者这样做。在IE中,调用window.CollectGarbage()方法会立即进行垃圾回收。在 Opera 7 及更高版本中,调用 window.opera.collect() 也会启动垃圾采集例程。
4.3.4 管理内存
通过使用具有垃圾采集机制的语言编写程序,开发人员通常不必担心内存管理。然而,JavaScript 在内存管理和垃圾回收方面面临的问题有点不同。其中最主要的是分配给 Web 浏览器的可用内存量通常少于分配给桌面应用程序的可用内存量。这样做的目的主要是出于安全考虑,目的是为了防止运行JavaScript的网页耗尽系统内存,导致系统崩溃。内存限制问题不仅会影响内存分配给变量,还会影响调用堆栈和线程中可以同时执行的语句数。
因此,确保使用最少的内存量可以提高页面的性能。优化内存使用的最佳方法是保存执行代码所需的数据。一旦数据不再有用,最好通过将其值设置为 null 来释放其引用——这种做法称为取消引用。这种做法适用于大多数全局变量和全局对象的属性。局部变量在离开执行环境时会自动取消引用,如以下示例所示:
函数 createPerson(名称){
var localPerson = new Object();
localPerson.name = 姓名;
返回本地人;
}
var globalPerson = createPerson("Nicholas");
// 手动解引用 globalPerson
globalPerson = null;
在此示例中,变量 globalPerson 获取 createPerson() 函数返回的值。在 createPerson() 函数中,我们创建一个对象并将其赋值给局部变量 localPerson,然后为该对象添加一个名为 name 的属性。最后,当这个函数被调用时,localPerson 作为函数值被返回并赋值给全局变量 globalPerson。由于 localPerson 在 createPerson() 函数完成后离开了它的执行环境,我们不需要显式地取消引用它。但是对于全局变量globalPerson,我们需要在不用的时候手动解引用,这就是上例最后一行代码的目的。
但是,取消引用一个值并不会自动回收该值占用的内存。取消引用的真正作用是从执行环境中获取值,以便下次垃圾采集器运行时可以回收它。
如果你想了解更多Java基础知识,可以点击评论区链接和我一起学java。本视频教程适合初学者,零基础入门!为学员带来全新的Java300套课程!Java零基础初学者自学Java必备优质教程_图文并茂学Java,让学习成为一种享受_哔哩哔哩_bilibili
的
汇总:ProcessDB实时/时序数据库——JAVA_API目录
web3.0会是下一代互联网的风口吗?
m0_68036862的博客
11-14
214
比如我曾经写过的文章里面的评论等等,我不管我发在哪个平台上,平台只是拿我们的数据,当平台不满足我的时候,我就拿数据授权新平台,以及之前的文章和评论。它更注重用户的交互。用户既是网站内容的观看者,也是网站内容的生产者。平台垄断,算法异化:基于海量数据的支持,平台可以根据大数据算法对其进行熟悉,向用户推荐的内容由算法控制。电商和搜索平台上的很多搜索都是付费排名,花钱买热门搜索等等。当前平台互联网:用户创造,