移除DOM元素后存在循环引用的JS对象会被垃圾回收吗?
引用关系校正
你梳理的大部分逻辑是对的,补充修正细节:
- 是 jQuery对象持有DOM元素的引用,DOM元素本身默认不会主动引用jQuery对象。你调用
data()方法存储数据时,jQuery会将键值对关联到对应DOM元素,本质是让DOM元素可以索引到你存储的MyDOMWrapper实例。 - MyDOMWrapper类实例通过
$elem属性持有jQuery对象的引用,这部分你的判断正确。 - 最终形成的是循环引用链:
MyDOMWrapper实例 → jQuery对象 → DOM元素 → (通过jQuery data关联)MyDOMWrapper实例
remove()执行后的垃圾回收表现
实际执行jQuery("#wrapped-elem").remove()后,你预期的内存释放行为会正常发生,不会被循环引用阻断,原因有两个:
- jQuery的
remove()方法除了将DOM元素从DOM树摘除之外,还会自动清理该DOM元素绑定的所有事件、以及通过data()存储的所有数据。这一步会直接断掉DOM元素到MyDOMWrapper实例的关联引用,循环链直接被打破。 - 现代所有主流浏览器的JavaScript引擎都采用标记清除的垃圾回收策略,哪怕存在循环引用,只要整个引用链上的所有对象都没有从根引用集(全局作用域、当前执行栈等)发起的可达引用,就会被统一标记为垃圾回收。你的代码里MyDOMWrapper实例是在IIFE中创建的,没有赋值给任何外部存活变量,IIFE执行完成后就没有从根集来的额外引用了,整个循环链的对象都是不可达状态,必然会被回收。
哪怕你不用jQuery的remove(),改用原生DOM方法removeChild()摘除元素,没有触发jQuery的data清理逻辑,现代浏览器的垃圾回收器依然可以识别到整个循环链不可达,正常回收所有关联内存,只有远古时期采用引用计数垃圾回收策略的浏览器才会出现循环引用导致的内存泄漏问题。
内容的提问来源于stack exchange,提问作者Adam Baranyai
相关产品推荐
相关产品推荐

