簡體   English   中英

剔除ViewModel計算的垃圾回收

[英]Knockout ViewModel computed garbage collection

我一直在嘗試在我的應用程序代碼中跟蹤垃圾回收的任何問題。 我已經將其簡化為純敲除代碼,並且根據計算屬性的創建方式收集創建的對象似乎存在問題。

請參閱以下JS小提琴: http : //jsfiddle.net/SGXJG/

  1. 開啟Chrome分析器。
  2. 拍攝堆快照
  3. 點擊全部制作
  4. 拍攝另一個堆快照
  5. 比較快照
  6. 正確收集Test1時,Test2和Test3仍保留在內存中。

請查看以下視圖模型代碼:

function ViewModel() {
    this.test1 = null;
    this.test2 = null;
    this.test3 = null;
}
ViewModel.prototype = {
    makeAll: function () {
        this.make1();
        this.make2();
        this.make3();
    },
    make1: function () {
        this.test1 = new Test1();
        this.test1.kill();
        delete this.test1;
    },
    make2: function () {
        this.test2 = new Test2();
        this.test2.kill();
        delete this.test2;
    },
    make3: function () {
        this.test3 = new Test3();
        this.test3.kill();
        delete this.test3;
    },
};
ko.applyBindings(new ViewModel());

這是三個測試類:

function Test1() {
    var one = this.one = ko.observable();
    var two = this.two = ko.observable();
    this.three = ko.computed(function () {
        return one() && two();
    });
}
Test1.prototype = {
    kill: function () {
        this.three.dispose();
    }
};

function Test2() {
    this.one = ko.observable();
    this.two = ko.observable();
    this.three = ko.computed(function () {
        return this.one() && this.two();
    }, this);
}
Test2.prototype = {
    kill: function () {
        this.three.dispose();
    }
};

function Test3() {
    var self = this;
    self.one = ko.observable();
    self.two = ko.observable();
    self.three = ko.computed(function () {
        return self.one() && self.two();
    });
    self.kill = function () {
        self.three.dispose();
    };
}

區別在於Test1的“三”計算不使用此函數或self來引用“一個”和“兩個”可觀察的屬性。 有人可以解釋這里發生了什么嗎? 我想閉包包含對象引用的方式有些問題,但我不明白為什么

希望我不會錯過任何東西。 讓我知道是否感謝您的任何答復。

與所有現代瀏覽器一樣,Chrome使用標記清除算法進行垃圾收集。 MDN

該算法假定了解一組稱為根的對象(在JavaScript中,根是全局對象)。 垃圾收集器會定期從這些根目錄開始,查找從這些根目錄引用的所有對象,然后從這些根目錄引用所有對象,依此類推。因此,從根目錄開始,垃圾收集器將查找所有可訪問對象並收集所有非對象。可達的對象。

垃圾收集器不運行的時候了,這就是為什么你仍然看到即使你取消引用它們(編輯Chrome的快照的對象:如前所述這里 ,運行堆快照首先運行垃圾收集器可能它不處理一切。因此不會清除對象;請參見下文。)

通常會觸發垃圾收集器的一件事是創建新對象。 我們可以使用您的示例對此進行驗證。 完成問題中的步驟后,單擊“ Make1”並拍攝另一個堆快照。 您應該看到Test2消失了。 現在再做一次,您會發現Test3也消失了。

更多注意事項:

  1. Chrome不會在垃圾回收期間清理所有內容。 “ [Chrome] ...在大多數垃圾回收周期中僅處理部分對象堆。” google.com )因此,我們看到需要運行幾次垃圾收集器才能清除所有內容。

  2. 只要清除了對某個對象的所有外部引用,該對象最終將由垃圾收集器清除。 在您的示例中,您甚至可以刪除dispose調用,所有對象都將被清除。

我認為這是一個經典的循環參考問題。

讓我們打電話:

var test2 = new Test2();

現在test2.three擁有test2的引用! 因為您從字面上要求敲除將一個function(){...}與該“此”對象(即test2對象)綁定。

由於test2自然擁有test2.three的引用,因此您現在在兩個對象之間有了一個循環引用!

您可以看到與您的Test3相同。

但對於Test1,我們稱之為:

var test1 = new Test1();

test1.three保存兩個對象的引用(test1.one和test2.two),test1保存三個引用(test1.one,test1.two和test1.three),沒有循環引用。

在其他一些語言(如Java和Objective-C)中,該語言支持弱引用來處理此類問題。 但是到目前為止,弱引用尚未在Javascript中實現。

+1感謝您的提問! 它使我的大腦有些旋轉,幫助我更多地了解了Javascript :)

我認為問題在於您在代碼中使用&&,它將返回一個布爾值,正確為“ true”。

this.three = ko.computed(function () {
    //                 !
    return this.one() && this.two();
},

那么this.three == true而不是self.one + self.two如果這是意圖? 當你處置

this.three.dispose();

您只是擺脫了布爾值。

有什么理由在“函數Test2()”中增加一個“ this”?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM