Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript映射是否有一定数量的键可以设置,或者是否有一定数量的键操作可以完成?_Javascript_Arrays_Maps_V8 - Fatal编程技术网

Javascript映射是否有一定数量的键可以设置,或者是否有一定数量的键操作可以完成?

Javascript映射是否有一定数量的键可以设置,或者是否有一定数量的键操作可以完成?,javascript,arrays,maps,v8,Javascript,Arrays,Maps,V8,所以我知道Javascript映射有一定数量的键可以存储(大约16.7米) 我试图测试是否可以(以一种非常丑陋的方式)从数组中删除最古老的元素。我注意到,无论我做什么,实际上并不是地图大小是一个限制因素,而是我做的操作数量限制了我 下面是一个示例代码: const map=newmap(); 设i=0; while(true){ i++; 集合(i,i); 如果(i%1000==0) log('INSERTED:',i',KEYS',MAP SIZE:',MAP.SIZE); } 功能集(键、

所以我知道Javascript映射有一定数量的键可以存储(大约16.7米)

我试图测试是否可以(以一种非常丑陋的方式)从数组中删除最古老的元素。我注意到,无论我做什么,实际上并不是地图大小是一个限制因素,而是我做的操作数量限制了我

下面是一个示例代码:

const map=newmap();
设i=0;
while(true){
i++;
集合(i,i);
如果(i%1000==0)
log('INSERTED:',i',KEYS',MAP SIZE:',MAP.SIZE);
}
功能集(键、值){
如果(地图大小>16770000){
数组.from(map.keys()).slice(0,10000).forEach(key=>map.delete(key));
log('已删除,当前映射大小:',map.size);
}
试一试{
map.set(键、值);
}捕获(e){
log('MAP SIZE:',MAP.SIZE',INSERTED:',key);
投掷e;
}

}
我深入研究了ECMA语言规范以查看映射()。您看到的行为似乎与规范一致,并且来自于Map的delete原型的规范定义

当使用
Map.prototype.delete(key)
删除地图元素时,规范仅要求将匹配
key
的元素设置为空

以下是从中复制和粘贴的定义:

采取以下步骤:
  • 设M为该值的最大值
  • 表演?RequireInternalSlot(M,[[MapData]])
  • 让条目为M.[[MapData]]的列表
  • 对于作为条目的元素的每个记录{[[Key]],[[Value]]}p,do
    A.如果p.[Key]]不为空且SameValueZero(p.[Key]],Key)为真,则
    一,。将p.[Key]]设置为空。
    二,。将p.[Value]]设置为空。
    iii.返回true
  • 返回false
  • 这里对我们来说最重要的是4a

    删除元素时,
    Map.prototype.delete
    检查每个记录p是否有p.[Key]]与提供的键参数匹配的元素

    找到时,p.[Key]]和p.[Value]]都设置为空

    这意味着,虽然密钥和值已经消失,不再存储或检索,但存储密钥和值的空间(元素本身)可能确实留在地图的存储中,并且仍然会占用幕后空间

    虽然本规范包含以下关于“empty”用法的注释

    值empty用作规范设备,以指示条目已被删除。实际实现可能会采取其他操作,例如从内部数据结构中物理删除条目

    …它仍然为实现在不回收空间的情况下简单地擦除数据打开了大门,这显然就是您的示例中所发生的情况

    那么...怎么样 对于
    set()
    ,函数首先使用匹配键检查现有元素,以改变的值,并跳过过程中的所有空元素。如果没有找到,则“将p[]追加为条目的最后一个元素”

    那么,关于什么? 在
    size
    的情况下,spec循环映射中的所有元素,并简单地为遇到的所有非空元素增加一个计数器


    我发现这真的很有趣。。。如果我不得不冒险猜测的话,我想在大多数情况下,寻找和移除空元素的开销被认为是不必要的,因为填充结构所必须达到的数量是如此之大,也就是说,因为地图容纳了这么多。我想知道删除一个空元素的时间和空间开销对于一个足够大的数据集来说会有多大,以满足它的需要。

    我修改了您的脚本(见下文),以查看在它可以在
    映射中再次插入键之前必须删除多少项

    结果是8388608(=16777216/2),带有
    节点v12.18.1
    (基于Chrome的V8 JavaScript引擎构建)

    这让我想起了一种常见的模式,即当基本数据结构几乎满时,其大小会翻倍。 因此,我在V8引擎中寻找实际的Map实现

    以下是V8开发对它的看法:

    ECMAScript 2015引入了一些新的数据结构,如Map、Set、WeakSet和WeakMap,所有这些结构都在后台使用哈希表

    这里有一个有趣的评论:

    请检查这一点,我在代码中做了一些更改,现在它正在工作。如果它仍然不工作,请告诉我

    我承认这不是最好的方法,而是重新初始化映射 对象将允许我们添加更多数据,但速度也会减慢 运行速度, 请打开控制台查看输出

    var-map=newmap();
    设i=0;
    var ke=[]
    while(true){
    i++;
    集合(i,i,map.size);
    如果(i%1000==0)
    log('INSERTED:',i',KEYS',MAP SIZE:',MAP.SIZE);
    }
    功能集(键、值、s){
    如果(s>=16730000){
    var arr=ke.slice(0,10000)
    ke.拼接(0,10000)
    arr.forEach(key=>map.delete(key));
    log('已删除,当前映射大小:',map.size);
    地图=新地图(地图);
    arr=[]
    }否则{
    试一试{
    按下(键)
    map.set(键、值);
    }捕获(e){
    log('MAP SIZE:',MAP.SIZE',INSERTED:',key);
    投掷e;
    }
    }
    
    }
    我不确定我是否理解这个问题,您能澄清一下吗?我在控制台中看到,最后的地图大小为16767216(如您所述,大约为16.7米)。最后一个插入的键是
    16777217
    ,它比最大贴图大小高10000,日志显示您在这之前删除了10000个键,所以我觉得一切都很好……如果我删除了10000个键,这难道不意味着我应该可以再设置10000个键吗?问题是我不能。最后一个插入的键实际上应该包含10000多个。但是它 HashTable is a subclass of FixedArray that implements a hash table that uses open addressing and quadratic probing. In order for the quadratic probing to work, elements that have not yet been used and elements that have been deleted are distinguished. Probing continues when deleted elements are encountered and stops when unused elements are encountered. - Elements with key == undefined have not been used yet. - Elements with key == the_hole have been deleted.
    map = new Map();
    let i = 0;
    
    while (true) {
      i++;
    
      try {
        map.set(i, i);
      } catch (e) {
        console.log(e);
        break;
      }
    
      if (i % 100000 === 0)
        console.log('inserted: ', i);
    }
    
    console.log('max map size:', map.size, 'inserted:', i);
    
    let j = 0;
    while (true) {
      j++;
    
      map.delete(j);
    
      if (j % 100000 === 0) {
        console.log('deleted: ', j, 'map size: ', map.size);
    
        if (map.size == 0) {
            break;
        }
      }
    
      try {
        map.set(i, i);
      } catch(e) {
        continue;
      }
    
      break;
    }
    
    console.log('deleted before inserting again: ', j);