Author: el_gringo
Date: Fri May  2 15:08:10 2008
New Revision: 54322

Modified:
   kukit/kukit.js/branch/el_gringo-memory-leaks-squeeze/kukit/eventreg.js
   kukit/kukit.js/branch/el_gringo-memory-leaks-squeeze/kukit/forms.js
   kukit/kukit.js/branch/el_gringo-memory-leaks-squeeze/kukit/plugin.js
   kukit/kukit.js/branch/el_gringo-memory-leaks-squeeze/kukit/resourcedata.js
   kukit/kukit.js/branch/el_gringo-memory-leaks-squeeze/kukit/utils.js
Log:
fixes some memory leaks on IE.
I've moved nodeHashes method to utils.js for dependences reason.
The main goal is to stores events and unregister them when unloading.
There's still memory leaks remaining, we also should unregister events when 
removing / replacing nodes.

I've used sIEve to detect leaks:

Modified: kukit/kukit.js/branch/el_gringo-memory-leaks-squeeze/kukit/eventreg.js
==============================================================================
--- kukit/kukit.js/branch/el_gringo-memory-leaks-squeeze/kukit/eventreg.js      
(original)
+++ kukit/kukit.js/branch/el_gringo-memory-leaks-squeeze/kukit/eventreg.js      
Fri May  2 15:08:10 2008
@@ -886,7 +886,7 @@
     // name and nodeHash are for speedup.
     if (typeof(nodeHash) == 'undefined') {
         name = oper.eventRule.kssSelector.name;
-        nodeHash = kukit.rd.hashNode(oper.node);
+        nodeHash = kukit.ut.hashNode(oper.node);
     }
     var rulesPerName = info[name];
     if (typeof(rulesPerName) == 'undefined') {
@@ -903,7 +903,7 @@
 this.bindOper = function (oper) {
     // Marks binding between binder, eventName, node.
     var name = oper.eventRule.kssSelector.name;
-    var nodeHash = kukit.rd.hashNode(oper.node);
+    var nodeHash = kukit.ut.hashNode(oper.node);
     var rulesPerName = this.checkOperBindable(oper, name, nodeHash);
     rulesPerName[nodeHash] = oper;
     // also store per node info
@@ -946,7 +946,7 @@
     if (typeof(rulesPerName) == 'undefined') {
         return null;
     }
-    var nodeHash = kukit.rd.hashNode(node);
+    var nodeHash = kukit.ut.hashNode(node);
     var oper = rulesPerName[nodeHash];
     if (typeof(oper) == 'undefined') {
         return null;

Modified: kukit/kukit.js/branch/el_gringo-memory-leaks-squeeze/kukit/forms.js
==============================================================================
--- kukit/kukit.js/branch/el_gringo-memory-leaks-squeeze/kukit/forms.js 
(original)
+++ kukit/kukit.js/branch/el_gringo-memory-leaks-squeeze/kukit/forms.js Fri May 
 2 15:08:10 2008
@@ -312,7 +312,7 @@
 };
 
 this.register = function(node, editor) {
-    var hash = kukit.rd.hashNode(node);
+    var hash = kukit.ut.hashNode(node);
     if (typeof(this.editors[hash]) != 'undefined') {
 ;;;     kukit.E = 'Double registration of editor update on node.';
         throw new Error(kukit.E);
@@ -324,7 +324,7 @@
 };
 
 this.doUpdate = function(node) {
-    var hash = kukit.rd.hashNode(node);
+    var hash = kukit.ut.hashNode(node);
     var editor = this.editors[hash];
     if (typeof(editor) != 'undefined') {
         editor.doUpdate(node);

Modified: kukit/kukit.js/branch/el_gringo-memory-leaks-squeeze/kukit/plugin.js
==============================================================================
--- kukit/kukit.js/branch/el_gringo-memory-leaks-squeeze/kukit/plugin.js        
(original)
+++ kukit/kukit.js/branch/el_gringo-memory-leaks-squeeze/kukit/plugin.js        
Fri May  2 15:08:10 2008
@@ -368,7 +368,7 @@
         phase = 1;
     } else {
         // get the phase from the node
-        phase = oper.node._kukitMark;
+        phase = kukit.ut.data(oper.node, 'kukitMark');
     }
     if (phase == 1 && ! oper.parms.initial) {
 ;;;     var msg = 'EventRule #' + oper.eventRule.getIndex() + ' mergeId [';
@@ -453,7 +453,7 @@
         kukit.engine.bindScheduler.addPost(func_to_bind, remark);
     }
     if (iloadoper) {
-        var phase = iloadoper.node._kukitMark;
+        var phase = kukit.ut.data(iloadoper.node, 'kukitMark');
         // For phase 2 we need to execute posponed, for phase1 immediately.
         // XXX it would be better not need this and do always postponed.
         if (phase == 2 || (phase == 1 && kukit.engine.initializedOnDOMLoad)) {

Modified: 
kukit/kukit.js/branch/el_gringo-memory-leaks-squeeze/kukit/resourcedata.js
==============================================================================
--- kukit/kukit.js/branch/el_gringo-memory-leaks-squeeze/kukit/resourcedata.js  
(original)
+++ kukit/kukit.js/branch/el_gringo-memory-leaks-squeeze/kukit/resourcedata.js  
Fri May  2 15:08:10 2008
@@ -321,7 +321,7 @@
             // XXX never rebind to any node again!
             // this compensates that cssQuery is returning
             // results out of the subtree
-            if (typeof(node._kukitMark) == 'undefined') {
+            if (typeof(kukit.ut.data(node, 'kukitMark')) == 'undefined') {
                 ruletable.add(node, this);
                 counter += 1;
                 }
@@ -871,7 +871,7 @@
 
 this.add = function(node, eventRule) {
     // look up node
-    var nodehash = rd.hashNode(node);
+    var nodehash = kukit.ut.hashNode(node);
     var nodeval = this.nodes[nodehash];
     if (typeof(nodeval) == 'undefined') {
         nodeval = {'node': node, 'val': {}};
@@ -888,7 +888,7 @@
     for (var nodehash in this.nodes) {
         var nodeval = this.nodes[nodehash];
         // XXX Mark the node, disabling rebinding in a second round
-        nodeval.node._kukitMark = phase;
+        kukit.ut.data(nodeval.node, 'kukitMark', phase);
         for (var id in nodeval.val) {
             var eventRule = nodeval.val[id];
             eventRule.bind(nodeval.node);
@@ -907,25 +907,6 @@
 this.initialize.apply(this, arguments);
 };
 
-rd.uid = 0;
-
-rd.hashNode = function(node) {
-    // It is, generally, not possible to use a node as a key.
-    // However we try to set this right.
-    // We generate an uniqueID on the node. This does not work
-    // on MSIE but it already has an uniqueID.
-    if (node == null) {
-        // null represents the document
-        return '<<DOCUMENT>>';
-    }
-    var id = node.uniqueID;
-    if (typeof(id) == 'undefined') {
-        id = rd.uid;
-        node.uniqueID = id;
-        rd.uid ++;
-    }
-    return id;
-};
 
 /*
 *  class MethodTable

Modified: kukit/kukit.js/branch/el_gringo-memory-leaks-squeeze/kukit/utils.js
==============================================================================
--- kukit/kukit.js/branch/el_gringo-memory-leaks-squeeze/kukit/utils.js 
(original)
+++ kukit/kukit.js/branch/el_gringo-memory-leaks-squeeze/kukit/utils.js Fri May 
 2 15:08:10 2008
@@ -564,7 +564,38 @@
 
 /* extracted from Plone */
 // cross browser function for registering event handlers
+ut.cache = {};
+ut.uid = 0;
+ut.data = function(node, key, value) {
+    var hash = ut.hashNode(node);
+    if (arguments.length == 3)
+        ut.cache[hash][key] = value;
+    
+    return ut.cache[hash][key];
+};
+ut.hashNode = function(node) {
+    // It is, generally, not possible to use a node as a key.
+    // However we try to set this right.
+    // We generate an uniqueID on the node. This does not work
+    // on MSIE but it already has an uniqueID.
+    if (node == null) {
+        // null represents the document
+        return '<<DOCUMENT>>';
+    }
+    var id = node.uniqueID;
+    if (typeof(ut.cache[id]) == 'undefined') {
+        if (!id) {
+            id = ut.uid++;
+            node.uniqueID = id;
+        }
+        ut.cache[id] = { node: node };
+    }
+    return id;
+};
 ut.registerEventListener = function(elem, event, func) {
+    var events = ut.data(elem, 'events') || [];
+    events.push({type: event, func: func});
+    ut.data(elem, 'events', events);
     if (elem.addEventListener) {
         elem.addEventListener(event, func, false);
         return true;
@@ -576,6 +607,36 @@
     return false;
 };
 
+ut.unRegisterEventListener = function(elem, event, func) {
+    if (elem.removeEventListener) {
+        elem.removeEventListener(event, func, false);
+        return true;
+    } else if (elem.detachEvent) {
+        var result = elem.detachEvent("on"+event, func);
+        return result;
+    }
+    return false;
+};
+
+ut.registerEventListener(window, 'unload', function() {
+    var t = [];
+    for (uid in ut.cache) {
+        var data = ut.cache[uid];
+        var node = data.node;
+        data.node = null;
+        if (typeof(data.events) != 'undefined')
+           for (var i = 0;i < data.events.length;++i) {
+                var event = data.events[i];
+                ut.unRegisterEventListener(node, event.type, event.func);
+           }
+        try {
+            delete node.uniqueID;
+        } catch(ex) {}
+        t.push(uid);
+        delete ut.cache[uid];
+    }
+});
+
 if (typeof(window) != 'undefined') {
     ut.registerEventListener(window, "load", kukit.bootstrap);
 }
_______________________________________________
Kukit-checkins mailing list
[email protected]
http://codespeak.net/mailman/listinfo/kukit-checkins

Reply via email to