Javascipt, that you do not know yet——Javascript Garbage Collection

来源:互联网 发布:市政给排水设计软件 编辑:程序博客网 时间:2024/05/24 03:20

With focusing on web client, my requirements for javascript become deeper and deeper, when I refine a javascript framework, and try to implement some cases of design pattern, my poor & basing on application's knowledge is shown without debt. I recall a painful experience, I think I can't ignore that defects, and decide to make up them, so , I am going to write a series of blogs:javascript, that you do not know yet, this is the first one, and is also a starting.

For any programming language, garbage collection is a commonplace, and it is also asked repeatedly in interview. In <Professional Javascript for Web Developers> 2rd Edition, I know the Garbage Collection of javascript.

Javascript has automatic garbage collection, it means run-time environment will be responsible  for managing RAM which is used by code processing. the principle of garbage collection is: find out variables that never be used yet, and release their RAM, sounds very simple. Therefore garbage collector will be activated in fixed time interval, and do this operation periodically.

So, our current question is how to judge a variable never be used? There are two kinds of type for judgement, the first one ismark-and-sweep, and the other isreference counting.

  • Mark-and-Sweep

This is the most common & popular type for garbage collection, when a variable enters environment (just like: declare a variable in a function), it marks the variable as 'Entering environment', when we leave the function, it marks the variable as 'Leaving environment'.

We can mark variable by using any ways, for example: we can mark variable via turning one specific bit for recording entering environment, or we can mark them in a list, how to mark? It's unimportant for garbage collection, the key is using which type.

when garbage collector is working, it will mark all RAM's variables, and then it cancels that variables in environment & variables reference by another variables' marks, that variables with mark will treat as pre-delete variables, because that variables in environment cannot use them, at last, the garbage collector will finish RAM collection work, that pre-delete variables will release their RAM space.

Until 2008, IE, Firefox, Opera, Chrome & Safari's javascript implementation are all used this strategy for Garbage Collection.

  • Reference counting

Another unusual garbage collection type is reference counting, it means environment will count every value's reference time.

If we declare a variable, and assign a reference-type value to it, it means the value's reference time is 1, and when it is assigned to another variable, its reference time is 2, by contrast, if one reference variable is pointed to another value, that previous pointed value's reference time will reduce 1, when its reference time is 0, it means we cannot call this value, thus we can recover its RAM. So when garbage collector is running, its RAM will be released.

Netscape Navigator 3.0 is the earliest browser which used Reference Counting strategy, but it got an issue soon, that iscircular reference, it means object A contains a pointer related object B, and object B also contains a pointer related object A.

For example:

function problem(){        var objectA = new Object();        var objectB = new Object();        objectA.someOtherObject = objectB;        objectB.anotherObject = objectA;}

In this case, objectA and objectB reference each other via its' property, that means their reference time are both 2. InMark-and-Sweep implementation, because after processing function, these two objects both leave action scope, therefore, that's no problem for this case. But inReference Counting implementation, after processing function, objectA and objectB will be kept on existing, bucause their reference counting will never be 0. If this function is called repeatedly, it'll cause there are many RAM can't be collected. so that, Netscape dropped this strategy in 4.0 version, and use the Mark-and-Sweep strategy.

However, that troubles caused by reference counting don't end.

As we known, there are some objects are not congenital javascript object in IE browser, for example, its BOM & DOM objects are based on COM (Component Object Model), and their garbage collection strategy is reference counting, so, even the javascript implementation of IE uses the Mark-and-Sweep, but javascript calls COM object still uses reference counting. In other words, as long as we call COM object in IE, it'll exist circular reference problem, please see the following case:

var element = document.getElementbyId('some_element');var myObject = new Object();myObject.element = element;element.someObject = myObject;

So in order to avoid these circular reference problem, we need to disconnect their reference relationship when we won't use them, for example:

myObject.element = null;element.someObject = null;

That's good habit! so when the garbage collector is running, they will be recovered.

========================================================


        随着工作重心转向前端,对于javascript需求的深度也越来越大,当开始用js写framework,写设计模式时,自己可怜的 、基于应用的知识已捉襟见肘,基础薄弱体现出来。痛定思痛,总不能对于缺陷视若无睹,决定花些时间把这部分补充起来,于是,萌生了整理一个系列文章的想法:javascript那些你所不知道的,这是第一篇,也是个一个 开始。

       垃圾回收机制对于任何语言来说,是个老生常谈的话题,也是面试中被问得最频繁的点。从《Javascript高级程序设计》一书中, 我了解到javascript的垃圾回收机制。

       Javascript有自动回收机制,这意味着运行环境会管理那些执行代码的内存,它的原理是:找出那些不再被使用的变量,释放它们的内存,听起来非常简单。垃圾回收器会在固定的时间间隔内被激活,定期执行清理操作。

       因此,我们现在的问题就变成了如何判断一个变量不再被使用?这里有两种判断方式:标记清除和引用计数。

  • 标记清除

      对于垃圾回收机制来说,这是最常见也是最流行的判断方式,当一个变量进入环境(比如:在一个方法中声明一个变量),它会将这个变量标记为“进入环境”,当我们离开这个方法,它会标记这个变量为“离开环境”。

      我们可以有标识方法,例如:我们能通过翻转某个特定的位来标识一个变量进入环境,或者,我们可以在一个列表中标记它,怎么标记变量,不是垃圾回收机制的关键,关键在于我们采用哪种方法判断(变量不再被使用,即:是否采用标记清除的方式判断变量不再被使用)。

      当垃圾回收器开始工作,它将内存中所有的变量标记一遍,取消那些处于环境中的和被其他引用型变量引用的变量的标记,这些依然带标记的变量将被视为预删除的变量,因为它们在环境中将不再被使用到,最后垃圾回收器将结束内存清理工作,这些预删除的变量将会释放其内存空间。

      直到2008年为止,IE,FireFox,Opera,Chrome,Safari的javascript实现在垃圾回收机制中都采用了这个策略。

  • 引用计数

      另一种不常见的垃圾收集类型叫引用计数,它意味着运行环境将统计每个变量被引用的次数。

      如果我们声明一个变量,并赋予它一个引用型的值,这意味着这个引用型的值的引用次数为1,当我们让另外一个变量指向这个引用型的值时,这个值的引用次数变为2,相比之下,当我们将某个变量指向到另外一个引用型的值时,那么之前它所指向的值的引用次数需要减1,当引用次数变为0,这意味着我们无法在访问到这个值,因此,我们可以回收它的内存,当垃圾回收机制运作时,它的内存空间将被释放。

     Netscape Navigator 3.0是最早使用引用计数策略的浏览器,但是,很快他们便遇到了一个问题:循环引用,它是指对象A包含一个指向对象B的指针,而对象B也包含一个指向对象A的指针。例如:

function problem(){        var objectA = new Object();        var objectB = new Object();        objectA.someOtherObject = objectB;        objectB.anotherObject = objectA;}

    在这个例子中,objectA和objectB通过各自的属性相互引用,也就是说,这两个对象的引用次数都是2。在采取标记清除策略的实现中,由于函数执行后,这两个对象都离开了作用域,因此这种相互引用将不是个问题,但是,采用引用计数策略的实现中,当函数执行完后,objectA和objectB还将继续存在,因为它们的引用次数将永远不会是0。假如这个函数被重复多次调用,就会导致大量的内存无法回收。为此,Netscape在4.0的版本中放弃了这种策略,转而采用标记清除策略。可是,引用计数导致的麻烦并未结束。

    我们知道,IE中有一些对象不是原生的javascript对象,例如,它的BOM和DOM对象就是基于COM(Component Object Model, 组件对象模型)的形式实现的,而COM对象的垃圾回收机制就是采用的引用计数策略,因此,即使IE的javascript实现使用了标记清除策略,但javascript访问的COM对象依然采用引用计数策略,换句话说,只要我们在IE中调用了COM对象,就存在循环引用的问题,请看下面这个例子:

var element = document.getElementbyId('some_element');var myObject = new Object();myObject.element = element;element.someObject = myObject;

为了避免循环引用的问题,我们需要在我们不再使用对象的时候,断开它们的引用关系,例如:

myObject.element = null;element.someObject = null;
这是一个好习惯!当垃圾回收器运行时,这些对象就能被正常回收了。

原创粉丝点击