I recently created a single-page ASP.NET MVC 3 with JS / jQuery UI (on top of an HTML view), the general idea of ββworking with Javascript is given below. I encounter problems with GC that do not free memory and leave a large number of elements (24,000 for the largest form, 15-20k and 1k depending on which form is loaded / unloaded) in the Detached DOM (can be viewed in the Chrome developer tools Heap Profiler).
var MainApp = function () { var meBase = this; this.activeObject = undefined; this.someFunc = function (val1, val2, etc) { //Some operation here } this.GetView(x, y, z) { if (meBase.activeObject != null) { meBase.BustActive(x, y, z); } else { if (condition) { //Load static html via $.get } else { switch (activeObjectSelector) { case CASEHERE: self.activeObject = new SomeObject(); self.activeObject.BeginInit(); break; case ..... } } } } this.BustActive = function (x, y, z) { if (meBase.activeObject.Destroy()) { meBase.activeObject = null; meBase.GetView(x, y, z); } } } var SomeObject = function () { var meBase = this; this.Bindings = []; this.Container = "#somecontainer"; //Some Properties this.Unbind = function () { $("#Somecontainer .bound").each(function () { if ($(this)["click"] && $.isFunction($(this)["click"])) { $(this).unbind('click'); } if ($(this)["blur"] && $.isFunction($(this)["blur"])) { $(this).unbind('blur'); } if ($(this)["change"] && $.isFunction($(this)["change"])) { $(this).unbind('change'); } if ($(this)["mouseenter"] && $.isFunction($(this)["mouseenter"])) { $(this).unbind('mouseenter'); } if ($(this)["mouseleave"] && $.isFunction($(this)["mouseleave"])) { $(this).unbind('mouseleave'); } }); //iterate through meBase.Bindings to remove any 'special' bindings such as 'live/die' } this.MapEvents = function () { //For Example $("#Somecontainer #element").click(meBase.SomeAction).addClass('bound'); // create object with removal function for 'special' bindings such as 'live/die' // and push it into meBase.Bindings; } this.InitUI = function () { //Setup tabs, datepickers, etc } this.Destroy = function () { meBase.Unbind(); //remove object fields and methods delete meBase.someProp; $(meBase.Container).empty(); delete meBase.BeginInit; delete meBase.InitUI; delete meBase.MapEvents; delete meBase.SomeAction; delete meBase; return true; } this.SomeAction = function () { //Do something productive..hopefully } this.ProcessView = function (data) { $("#MainContainer").fadeOut(150, "swing", function () { $(this).empty().append(data); }); } this.LoadView = function () { $.ajax({ url: '/somewhere/something', type: 'GET', success: meBase.ProccessView, error: SomeGlobalObject.LogAjaxError }); } this.BeginInit = function () { //Load pages via ajax meBase.LoadView(); meBase.InitUI(); meBase.MapEvents(); return true; } }
I tried iterating with javascript to remove events and elements in the .Destroy () function, and this significantly reduced the number of elements left in a separate DOM compared to $ (container) .empty () or $ (container) .remove () . But my memory never collects back, it constantly grows during each loading / unloading. There are drops at random intervals, but not the amount I would expect. Is it normal for so many elements to stay the same, or is there some kind of fundamental problem with how my code works?
Thanks for taking the time to read this!
First post, please be careful ...
source share