QuickJS 源码剖析:垃圾回收原理

JavaScript07

QuickJS 源码剖析:垃圾回收原理,第1张

QuickJS 是一个轻量级的 JavaScript 引擎,可以代替 V8 实现 JS 脚本的执行,如果要使用 QuickJS,必须要弄懂其垃圾回收原理,否则容易出现野指针或内存泄漏,从而导致程序崩溃,本文通过源码剖析 QuickJS 的垃圾回收原理。

QuickJS 是使用引用计数法来判断对象是否可以被释放,引用计数法非常简单,通过给对象分配一个计时器来保存该对象被引用的次数,如果该对象被其它对象引用就会加1,如果删除引用就会减1,当引用的计数器为0时,那么就会被回收。

JSRuntime 是 QuickJS 最底层的执行环境,不使用的时需要及时释放。

一个 JSRuntime 可以创建多个 Context,每个 Context 之间是相互隔离的,不使用的时需要及时释放。

如果我们需要自己创建和关联JS对象时,我们需要处理好引用问题,必须通过 c 创建一个JSValue对象,那么我们就需要手动释放它,否则就会导致内存泄漏,同时我们也不能多次释放,这也会导致野指针,从而导致程序崩溃,如果我们只是纯粹运行js脚本就无需我们关心这个问题,引擎已经处理好了。

通过上面示例,我们得知引用计数法是通过JS_DupValue记录引用+1,JS_FreeValue引用减1实现计数,接下来就通过源码分析如何实现。

引用计数器头是一个结构体,目前只有一个int值,用于记录对象的引用次数。

引用计数器+1

JS_FreeValue 处理引用计数器-1,如果引用属于小于0时候就会执行垃圾回收,这里引入引用计数器最大的问题,如果a引用b,b也引用了a,这样的相互应用是不是就会导致a和b都无法回收?

JS_RunGC 函数就是用来解决相互引用问题,会在特定的时机触发。

经过上面两个函数,tmp_obj_list 就只会剩下环形引用的对象,gc_free_cycles() 回收 tmp_obj_list 列表的对象,并且对属性的引用-1。

定义:当一个函数的返回值是另一个函数,并且返回的那个函数调用了父函数内部的其他变量,当返回的函数被外部调用时,就产生了闭包。

表现形式:是函数外部能调用函数内部定义的变量。

工作原理:利用js中的垃圾回收机制,当一个函数被调用时,开辟一个新的空间,函数调用结束,释放空间,垃圾回收机制调用结束的函数时,发现函数中的变量被其他的函数调用,这些变量不会被释放,会永久保存在内存,只有退出程序才会释放。

闭包的局限性:滥用闭包会造成内存的泄漏由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大。在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。会改变父函数内部变量的值。