Toon posts:

Memory leak of fata morgana?

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik vermoed last te hebben van een memory leak in mijn webapp. Ik was het geheugenverbruik aan het monitoren in de memory timeline van de Chrome Developer Tools en verwachte om op een bepaald punt, na het geforceerd runnen van de GC, het geheugenverbruik te zien afnemen. Dit gebeurde echter niet.

Hierop heb ik mij ingelezen over het gebruik van de heap snapshot functionaliteit van Chrome. De documentatie hierover is eerder spartaans maar ik denk toch een redelijk goed idee te hebben van hoe ik de data moet interpreteren.

Kwestie van hier geen paar duizend regels JS-code te moeten plaatsen heb ik een test-case uitgewerkt. De test-case is relatief lang maar geen paniek, het meeste is "mise en scène".

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
<!DOCTYPE html>

<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>Memory Leak</title>
</head>
<body>
    <script type="text/javascript">

        /*jslint browser: true, plusplus: true, devel: true*/

        (function () {

            "use strict";

            var sceneThree = function sceneThree(mn) {

                    var crap = [],
                        instance = {},

                        update = function update() { /*empty*/ },
                        getCrap = function getCrap() {

                            return crap;
                        },
                        initialise = function initialise() {

                            var i;

                            for (i = 0; i < 10000; ++i) {

                                crap.push({ three: "3" });
                            }

                            alert("Take heap snapshot");
                        };

                    instance.update = update;
                    instance.getCrap = getCrap;
                    initialise();

                    return instance;
                },

                sceneTwo = function sceneTwo(mn) {

                    var crap = [],
                        instance = {},

                        update = function update() {

                            mn.setScene(sceneThree(mn));
                        },
                        getCrap = function getCrap() {

                            return crap;
                        },
                        initialise = function initialise() {

                            var i;

                            for (i = 0; i < 10000; ++i) {

                                crap.push({ two: "2" });
                            }
                        };

                    instance.update = update;
                    instance.getCrap = getCrap;
                    initialise();

                    return instance;
                },

                sceneOne = function sceneOne(mn) {

                    var crap = [],
                        count = 1,
                        nextScene = sceneTwo(mn),
                        instance = {},

                        update = function update() {

                            if (count >= 10) {

                                mn.setScene(nextScene);

                                return;
                            }

                            crap[0] = { one: "1" }; //making absolutely sure crap can't be GC'ed (me going insane, just ignore)
                            nextScene.getCrap(); //imagine doing something with crap, apparently this line in combination with the delayed setScene() causes a memory leak, however the crap of this scene is nowhere to be found in the heap snapshot
                            ++count;
                        },
                        getCrap = function getCrap() {

                            return crap;
                        },
                        initialise = function initialise() {

                            var i;

                            for (i = 0; i < 10000; ++i) {

                                crap.push({ one: "1" });
                            }
                        };

                    instance.update = update;
                    instance.getCrap = getCrap;
                    initialise();

                    return instance;
                },

                main = function main() {

                    var crap = [],
                        scene,
                        instance = {},

                        setScene = function setScene(scn) {

                            scene = scn;
                        },
                        getCrap = function getCrap() {

                            return crap;
                        },
                        run = function run() {

                            window.setTimeout(run, 100);
                            scene.update();
                        },
                        initialise = function initialise() {

                            var i;

                            for (i = 0; i < 10000; ++i) {

                                crap.push({ zero: "0" });
                            }

                            scene = sceneOne(instance);
                            run();
                        };

                    instance.setScene = setScene;
                    instance.getCrap = getCrap;
                    initialise();
                };

            main();
        }());
    </script>
</body>
</html>


De test-case bestaat uit vier classes. De main class welke een "animatie loop" opzet en hierin de update method called van de actieve scene en drie scene classes welke in de update method niets meer doen dan de volgende scene activeren.

Elke class bevat verder ook een member genaamd crap. Deze member is een array gevuld met, de naam zegt het al, brol. Wegens de grote retained size van deze member kan je deze snel terug vinden in de heap snapshot.

Hetgeen ik verwacht te zien in de heap snapshot na het runnen van deze test-case zijn de crap members van de main- en sceneThree-classes. Echter vind ik naast deze ook nog de crap member van de sceneTwo class terug. De retaining tree zegt mij closure met zijn publieke methods maar wat daar boven zit?

Nu komt het vreemde. De crap member van sceneTwo verdwijnt wanneer ik:
  • lijn 93 in commentaar zet;
  • lijn 87 verplaats naar het einde van de method (en setScene dus onmiddellijk call in plaats van het even uit te stellen, minder lang uitstellen werkt overigens ook).
Memory leak of fata morgana?

Verduidelijking
Ik wil weten of mijn analyse van wat ik zie correct is en indien ja wat de oorzaak is.

[ Voor 0% gewijzigd door Verwijderd op 17-01-2013 10:13 . Reden: Zie kop verduidelijking. ]