1

已经以多种不同的形式提出了这个问题,但我不确定我的情况是否完全适用。

说,我有一个 node.js 程序。我的程序通过实例化一个名为 Stream 的类连接到一个 Stream。在 Stream 中实例化了一个 StreamParser 类,其中包含几个定时器。

当我Stream.destroy()的原始流时,保存 StreamParser 的对象设置为null. 内存空间会发生什么,计时器会发生什么?似乎我的计时器仍在运行,除非我明确表示clearTimeout它们......

所以,嵌套结构:

new Stream()
    -> this.stream = new StreamParser()
        -> this.intv = setInterval(function() { // code }, 1000);

// Streams are destroyed like this:
Stream.destroy()
    -> calls this.stream.destroy(function() { 
            self.stream = null;
            // stream is null. but timers seem to be running. So, is stream still in memory?
        }

我有点困惑。更多扩展的代码示例:

// main call.

var stream = new Stream();

stream.connect();

setTimeout(function() {
    stream.destroy(function() {
        stream = null;
    });
}, 60000);


/** ############# STREAM ############### **/

function Stream() {
    this.stream = null;
    this.end_callback = null;
}

Stream.prototype.connect = function() {
    var self = this;

    new StreamParser('stream.com', function(stream) {
        self.stream = stream;

        self.stream.on('destroy', function(resp) {
            if(self.end_callback !== null && typeof self.end_callback === 'function') {
                var fn = self.end_callback;

                self.end_callback = null;
                self.stream = null;

                fn();
            } else {
                self.stream = null;
            }
        });
    });
}

Stream.prototype.destroy = function(callback) {
    this.end_callback = callback;
    this.stream.destroy();
}


/** ############# STREAM PARSER ############### **/

function StreamParser(uri, callback) {
    var self = this;

    this.conn = null;
    this.callback = null;

    this.connectSocket(uri, function(conn) {
        self.conn = conn;
        self.callback(conn);
    })

    setInterval(function() {
        self.checkHeartbeat();
    }, 1000);
} 

StreamParser.prototype.checkHeartbeat = function() {
    // check if alive
}

StreamParser.prototype.destroy = function() {
    this.conn.destroy();
    this.emit('destroy', 'socket was destroyed');
}
4

2 回答 2

3

在 javascript 中,您不会像在 c++ 等语言中那样显式地销毁对象。相反,当您通过将变量设置为 来清除对该对象的引用时null,这会使该对象更有资格进行垃圾收集(现在少了一个包含对该对象的引用的脚本)。但是,如果有任何其他对该对象的引用,那么它仍然不会被垃圾回收。

在这种情况下,您的计时器在其闭包(围绕它们的函数)中保存对您的对象的引用,这意味着仍然存在对流的引用,因此垃圾收集器不会清理它。系统保留对您的计时器的引用,以便它们将正常执行(无论您对流对象做什么),并且当它们触发时,它们将按照设计的方式对(仍然存在的)流对象进行操作。

如果要停止计时器,则需要显式使用clearTimeout()它们。这将导致包含对流对象的其他引用的计时器闭包随后被释放,如果在代码中的其他任何地方没有对流对象的其他引用,则 javascript 垃圾收集器将能够实际释放流对象使用的内存。

当流对象最终被垃圾回收时,它将导致它对它所引用的任何子对象的引用不再是活动的。如果这些对象本身在您的代码中没有其他引用指向它们,那么它们也将被垃圾回收。但是,如果某些其他代码也指向这些子对象之一,则该子对象将被保留以供该其他引用使用。

于 2012-08-13T10:17:49.040 回答
2

JavaScript 使用垃圾收集,这意味着任何人都无法访问的对象将被“遗忘”。它没有被“删除”——没有对对象执行其他操作。相反,它占用的内存将再次可用于创建新对象。

所以你需要问这个问题:还有人可以看到孩子吗?

在计时器的情况下,浏览器需要以某种方式执行它们,因此它必须在某个地方有一个列表。这意味着有两个地方引用了计时器:您的代码和浏览器中的某处。如果您忘记了您的对象,只要浏览器需要计时器,浏览器仍然会保持其引用处于活动状态。

于 2012-08-13T10:17:20.243 回答