这有点难以解释,但我会尝试一下:
在 Node.js 服务器应用程序中,我想处理可以同时在多个地方使用的数据对象。主要问题是,这些对象仅由对象 ID 引用并从数据库加载。
但是,一旦对象已加载到一个作用域中,则不应在请求时再次加载该对象,而应返回相同的对象。
这引出了垃圾收集的问题:一旦某个对象在任何范围内不再需要,就应该将其完全释放,以防止整个数据库始终保留在服务器内存中。但问题就在这里:
我可以想到两种方法来创建这样的场景:要么使用全局对象引用(这会阻止收集任何对象),要么真正复制这些对象,但以一种方式同步它们,即每次一个范围内的属性发生更改时,通知其他实例有关该更改的信息。因此,每个实例都必须注册一个事件处理程序,该事件处理程序又指向该实例,从而防止它再次被收集。
有没有人为我没有意识到的这种情况提出解决方案?还是我对垃圾收集器的理解存在误区?
我想避免的是对内存中的每个对象进行手动引用计数。每次从任何集合中删除对象时,我都必须手动调整引用计数(js 中甚至没有析构函数或“引用减少”事件)
最佳答案
使用 weak
模块,我实现了一个 WeakMapObj
,它的工作方式就像我们最初希望 WeakMap
一样工作。它允许您使用基元作为键,使用对象作为数据,并且数据通过弱引用保留。并且,当项目的数据被 GC 时,它会自动从 map 中删除项目。事实证明这相当简单。
const weak = require('weak');
class WeakMapObj {
constructor(iterable) {
this._map = new Map();
if (iterable) {
for (let array of iterable) {
this.set(array[0], array[1]);
}
}
}
set(key, obj) {
if (typeof obj === "object") {
let ref = weak(obj, this.delete.bind(this, key));
this._map.set(key, ref);
} else {
// not an object, can just use regular method
this._map.set(key, obj);
}
}
// get the actual object reference, not just the proxy
get(key) {
let obj = this._map.get(key);
if (obj) {
return weak.get(obj);
} else {
return obj;
}
}
has(key) {
return this._map.has(key);
}
clear() {
return this._map.clear();
}
delete(key) {
return this._map.delete(key);
}
}
我能够在测试应用程序中对其进行测试,并确认它在垃圾收集器运行时按预期工作。仅供引用,仅使一两个对象符合垃圾收集条件并不会导致垃圾收集器在我的测试应用程序中运行。我不得不强制调用垃圾收集器才能看到效果。我认为这在真正的应用程序中不会成为问题。 GC 将在需要时运行(可能仅在有合理数量的工作要做时运行)。
<小时/>您可以使用这个更通用的实现作为对象缓存的核心,其中项目将保留在 WeakMapObj
中,直到不再在其他地方引用为止。
这是一个使 map 完全私有(private)的实现,因此无法从 WeakMapObj
方法外部访问它。
const weak = require('weak');
function WeakMapObj(iterable) {
// private instance data
const map = new Map();
this.set = function(key, obj) {
if (typeof obj === "object") {
// replace obj with a weak reference
obj = weak(obj, this.delete.bind(this, key));
}
map.set(key, obj);
}
// add methods that have access to "private" map
this.get = function(key) {
let obj = map.get(key);
if (obj) {
obj = weak.get(obj);
}
return obj;
}
this.has = function(key) {
return map.has(key);
}
this.clear = function() {
return map.clear();
}
this.delete = function(key) {
return map.delete(key);
}
// constructor implementation
if (iterable) {
for (let array of iterable) {
this.set(array[0], array[1]);
}
}
}
关于javascript - Node.js 垃圾收集和同步对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47025893/