通过Javascript WeakMaps进行垃圾回收缓存
我想在JS中缓存大对象。这些对象是通过键检索的,缓存它们是有意义的。但是它们不能一次装入内存,所以我希望在需要时对它们进行垃圾收集——GC显然知道得更好 使用其他语言中的WeakReference或WeakValueDictionary创建这样的缓存是非常简单的,但是在ES6中,我们使用了WeakMap,其中键很弱 那么,是否可以创建类似于通过Javascript WeakMaps进行垃圾回收缓存,javascript,caching,garbage-collection,ecmascript-6,ecmascript-harmony,Javascript,Caching,Garbage Collection,Ecmascript 6,Ecmascript Harmony,我想在JS中缓存大对象。这些对象是通过键检索的,缓存它们是有意义的。但是它们不能一次装入内存,所以我希望在需要时对它们进行垃圾收集——GC显然知道得更好 使用其他语言中的WeakReference或WeakValueDictionary创建这样的缓存是非常简单的,但是在ES6中,我们使用了WeakMap,其中键很弱 那么,是否可以创建类似于WeakReference的东西,或者从WeakMap创建垃圾收集缓存 是否可以从WeakMap生成WeakReference或从WeakMap生成垃圾回收缓
WeakReference
的东西,或者从WeakMap
创建垃圾收集缓存
是否可以从WeakMap生成WeakReference或从WeakMap生成垃圾回收缓存
答:两个问题的答案都是“否”。有两种情况下,哈希映射较弱是有用的(您的哈希映射似乎适合第二种情况):
WeakReference
的设计者并没有为上面定义的两种用法实现单独的类,而是将其设计成可以在某种程度上对其中任何一种都可用,尽管不是很好
在键定义相等表示引用标识的情况下,
WeakHashMap
将满足第一种使用模式,但第二种使用模式将毫无意义(持有对语义上与存储密钥相同的对象的引用的代码将持有对存储密钥的引用,并且不需要WeakHashMap为其提供引用)。在键定义其他形式的相等的情况下,表查询返回对存储对象的引用以外的任何内容通常都没有意义,但避免存储引用使键保持活动状态的唯一方法是使用WeakHashMap
并让客户端检索弱引用,检索键存储在其中的引用,并检查它是否仍然有效(在WeakHashMap
返回WeakReference
和检查WeakReference
本身之间可以收集它).正如其他答案所提到的,不幸的是,没有像Java/C中那样的弱映射
作为一种解决方法,我创建了这个CacheMap
,它可以保留最大数量的对象,并跟踪它们在设定时间段内的使用情况,以便您:
"use strict";
/**
* This class keeps a maximum number of items, along with a count of items requested over the past X seconds.
*
* Unfortunately, in JavaScript, there's no way to create a weak map like in Java/C#.
* See https://stackoverflow.com/questions/25567578/garbage-collected-cache-via-javascript-weakmaps
*/
module.exports = class CacheMap {
constructor(maxItems, secondsToKeepACountFor) {
if (maxItems < 1) {
throw new Error("Max items must be a positive integer");
}
if (secondsToKeepACountFor < 1) {
throw new Error("Seconds to keep a count for must be a positive integer");
}
this.itemsToCounts = new WeakMap();
this.internalMap = new Map();
this.maxItems = maxItems;
this.secondsToKeepACountFor = secondsToKeepACountFor;
}
get(key) {
const value = this.internalMap.get(key);
if (value) {
this.itemsToCounts.get(value).push(CacheMap.getCurrentTimeInSeconds());
}
return value;
}
has(key) {
return this.internalMap.has(key);
}
static getCurrentTimeInSeconds() {
return Math.floor(Date.now() / 1000);
}
set(key, value) {
if (this.internalMap.has(key)) {
this.internalMap.set(key, value);
} else {
if (this.internalMap.size === this.maxItems) {
// Figure out who to kick out.
let keys = this.internalMap.keys();
let lowestKey;
let lowestNum = null;
let currentTime = CacheMap.getCurrentTimeInSeconds();
for (let key of keys) {
const value = this.internalMap.get(key);
let totalCounts = this.itemsToCounts.get(value);
let countsSince = totalCounts.filter(count => count > (currentTime - this.secondsToKeepACountFor));
this.itemsToCounts.set(value, totalCounts);
if (lowestNum === null || countsSince.length < lowestNum) {
lowestNum = countsSince.length;
lowestKey = key;
}
}
this.internalMap.delete(lowestKey);
}
this.internalMap.set(key, value);
}
this.itemsToCounts.set(value, []);
}
size() {
return this.internalMap.size;
}
};
我认为这个问题是专门针对JavaScript的,而不是Java或其他具有
WeakReference
/WeakHashMap
的语言。问题是JavaScript只有类似于WeakHashMap
的东西,但不等同于WeakReference
@Qantas94Heavy:确实如此。也许我应该这样做我认为JavaScript只支持第一个,不幸的是,这不是我怀疑OP真正想要的。你喜欢编辑吗?在JC中就是。因此,使用WeakRefs进行缓存没有任何意义。如果需要缓存大型对象,请使用浏览器的缓存(如果它们来自服务器)或。在节点环境中使用Redis或Memcached。
// Keeps at most 10 client databases in memory and keeps track of their usage over a 10 min period.
let dbCache = new CacheMap(10, 600);