Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Model instances are not getting clear. #2518

Open
siddesh94 opened this issue Feb 22, 2020 · 5 comments
Open

Model instances are not getting clear. #2518

siddesh94 opened this issue Feb 22, 2020 · 5 comments
Labels

Comments

@siddesh94
Copy link

siddesh94 commented Feb 22, 2020

Scenario 1:
snapshot 2 : i am creating 100 instances on button click
snapshot 3: i am deleting those 100 objects on button click.

before
after
afterx2

so after destroying object in heap snapshot there is not any instance present. works fine

Scenario 2
snapshot 2: i am creating 100 instances on button click
step 2: change few value in input field which is bind to the object
snapshot 3: i am deleting those 100 objects on button click.

before
value change
reference there

so after destroying object in heap snapshot there is those few instance present.

i want to know how can i destroy those completely

code:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.5.1/knockout-latest.min.js"
        type="text/javascript"></script>
</head>

<body>
    <button onclick="createObj()"> Create 100 Objects </button>
    <button onclick="destroyObj()">Destroy All Object</button>
    <div id='liveExample'>

    </div>

    <script>

var subscriptions = [];
var instances = [];
        var  ViewModel = function (first, last) {
            this.firstName = ko.observable(first);
            this.lastName = ko.observable(last);

            this.fullName = ko.computed(function () {
                return this.firstName() + " " + this.lastName();
            }, this);

            subscriptions.push(this.firstName.subscribe(function (newValue) {
                   console.log();
                }));
            subscriptions.push(this.lastName.subscribe(function (newValue) {
               console.log();
            }));
        };
        function createObj() {
            for (var  i = 0; i < 100; i++) {
                var input1 = document.createElement('input');
                var input2 = document.createElement('input');
                var span = document.createElement('span');

                input1.setAttribute('data-bind', 'value: firstName');
                input2.setAttribute('data-bind', 'value: lastName');
                span.setAttribute('data-bind', 'text: fullName');

                var main = document.createElement('div');
                main.setAttribute('id', 'test' + i);
                var dom = document.getElementById('liveExample');
                main.appendChild(input1);
                main.appendChild(input2);
                main.appendChild(span);

                dom.appendChild(main);
                var  instance = 'instance' + i;
                instance = new ViewModel("Testing", "Knockout");
                ko.applyBindings(instance, document.getElementById('test' + i));
            }
        }




        function destroyObj() {
            var childNode = document.getElementById('liveExample').childNodes;
            var  length = childNode.length;
            for (var  i = 0; i <= length; i++ ) {
                childNode[i].remove();
                length -= 1;
                i = 0;
            }
            console.log(ko.isObservable());
            for (var  i = 0; i < subscriptions.length; i++) {
                subscriptions[i].dispose()
            }
        }
    </script>
</body>

</html>
@mbest
Copy link
Member

mbest commented Feb 23, 2020

Instead of childNode[0].remove(); try using Knockout's ko.removeNode.

@siddesh94
Copy link
Author

hey @mbest thanks for your reply
i tried ko.removeNode(childNode[i]);
but it doesn't work,
still the object which are changed are there in the memory

do we have any other alternative to solve this problem???

@justlep
Copy link

justlep commented Mar 3, 2020

Looks like the change event listeners on the input elements are preventing garbage collection of a respective viewmodel instance once a change event was fired. Knockout's internal registerEventListener() (used by the value binding and most other dom-related bindings) doesn't explicitly remove the added event listener upon dom removal. Modern browsers supposedly take care of that automatically some say, but MDN doesn't mention this to be optional.

So the most simple and clean fix would be to add explicit event listener removal straight into Knockout's registerEventListener():
https://gist.github.com/justlep/4b45e2d863c852050e712942c0d62ce9/revisions

This fixed the leak for me.

(It's mandatory to use ko.removeNode() for it to work, of course).

@mbest
Copy link
Member

mbest commented Feb 28, 2021

According to https://stackoverflow.com/a/26442188 we should not need to call removeEventListener.

@mbest mbest added the waiting label Feb 28, 2021
@yswang0927
Copy link

Knockout needs to provide ko.disposeBindings(element) to clear all bindings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants