• WeakMap 本身释放,而 keyObject 没有释放的情况下,value 会释放吗?


    博客园markdown不太好看,可以转到git阅读https://sologgfun.github.io/look/

    const keyObject = ['keyObject'];
    new WeakMap().set(keyObject, ['value']);
    

    问题:现在 ['value'] 会被释放吗?

    听说WeakMap是o(1)复杂度的,而且不会存在内存泄漏问题,那么就只有一种实现机制,就是value直接通过一个隐形键挂在keyObject上。

    但如果是这样,而WeakMap本身又没有引用它之前添加过那些内容,那么是不是如果keyObject不释放,即便WeakMap实例释放了,通过该WeakMap实例添加在keyObject上的value是不是也都不会释放,从而形成另一种内存泄漏?

    jsperf.com只能测试性能,不知道内存泄漏该如何测试?


    答案:会正确被释放

    测试过程:

    [1]Chrome DevTools 控制台上有一个小众的 API 叫

    queryObjects()
    

    ,它可以从原型树上反查所有直接或间接的继承了某个对象的其它对象,比如

    queryObjects(Array.prototype)
    

    可以拿到所有的数组对象,

    queryObjects(Object.prototype)
    

    则基本上可以拿到页面里的所有对象了(除了继承自Object.create(null)的对象之外)。而且关键是这个 API 会在内存里搜索对象前先进行一次垃圾回收

    【测试1】

    const key = new WeakMap();
    const map = new WeakMap();
    map.set(key, new WeakMap());
    undefined;
    

    在chrome控制台运行

    image

    查到了 3 个对象,符合预期

    【测试2】

    const key = new WeakMap();
    new WeakMap().set(key, new WeakMap());
    undefined;
    
    

    在chrome控制台运行

    image

    只有一个WeakMap没有被回收


    那么WeakMap是怎么做到的呢?

    核心在于WeakMap上的kv对是弱引用的

    V8 的实现,是在 GC 上开洞的
    https://github.com/v8/v8/blob/4b9b23521e6fd42373ebbcb20ebe03bf445494f9/src/objects/hash-table.h#L336

    https://github.com/v8/v8/blob/4b9b23521e6fd42373ebbcb20ebe03bf445494f9/src/heap/scavenger.cc#L465WeakMap

    里用的就是这个 EphemeronHashTable,EphemeronHashTable 存储着的键和值都是弱引用

    let wm = new WeakMap([[k1, v1], [k2, v2]]) // vm = {k1:v1, k2:v2}
    
    wm.size // no such property
    
    wm.keys(); // no such function
    
    wm.forEach(...) // unable to be iterated
    
    

    WeakMap有2个特点

    1. 属性不可枚举
    2. key必须是Object类型

    看一下WeakMap的polyfill

    var WeakMap = function() {
        this.name = '__wm__' + uuid()
    };
    
    WeakMap.prototype = {
        set: function(key, value) {
            Object.defineProperty(key, this.name, {
                value: [key, value],
            });
            return this;
        },
        get: function(key) {
            var entry = key[this.name];
            return entry && (entry[0] === key ? entry[1] : undefined);
        },
        ...
    };
    
    1. weakmap.set(key, val)事实上是直接通过Object.defineProperty给这个key加了一个新属性

    —— WeakMap的key必须是Object类型的原因

    1. 相比Map,WeakMap持有的只是每个键值对的“弱引用”,不会额外开内存保存键值引用。这意味着在没有其他引用存在时,垃圾回收器能正确处理key指向的内存块。

    —— WeakMap的key不可枚举的原因


    延伸阅读

    1.Object.defineProperty(obj, "prop", propDesc)和obj.prop = value的区别?

    [译]JavaScript中的属性:定义和赋值的区别

    2.什么是弱引用?

    垃圾回收机制不考虑对该对象的引用。

    也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象是否还在该弱引用的结构中。

    WeakMap不能遍历,是因为成员都是弱引用,随时可能消失,遍历机制无法保证成员的存在,很可能刚刚遍历结束,成员就取不到了。


    参考资料

    1. https://www.zhihu.com/question/344771857
    2. https://www.jianshu.com/p/8c4ffa77b346
    3. http://es6.ruanyifeng.com/#docs/set-map#WeakSet
  • 相关阅读:
    查看mysql日志
    Redis配置和常用命令
    任务
    如何让maven 将工程依赖的jar 复制到WEB-INF/lib 目录下
    Tomcat8安装, 安全配置与性能优化(转)
    Web.xml详解(转)
    php精度比较函数bccomp
    php找到字符数组里最左匹配长度的字符(最长公共前缀匹配算法)
    PHP实现curl post和get
    Jquery 跨Dom窗口操作
  • 原文地址:https://www.cnblogs.com/cndotabestdota/p/11552309.html
Copyright © 2020-2023  润新知