Loading ...
Sorry, an error occurred while loading the content.

Substantial memory leak when tearing down and building submenus.

Expand Messages
  • Ania
    The code below demonstrates the issue. The leak is VERY pronounced in IE, a bit less so in FF. In our application as the user selects objects from a table, an
    Message 1 of 1 , Mar 4, 2010
    View Source
    • 0 Attachment
      The code below demonstrates the issue. The leak is VERY pronounced in IE, a bit less so in FF.

      In our application as the user selects objects from a table, an ajax call goes out to get data for that object. As a consequence one of the existing submenus is deleted and a new 3 level cascading submenu is build and rendered. Each time that happens a substantial memory leak occurs.

      This interaction is fundamental to the working of our application, so ANY resolutions or ideas on how to cleanly and completely delete existing submenu will be most appreciated.

      Ania.


      <script type="text/javascript" >
      var menuData =
      [
      { text:"Test", submenu: { id:"Test", itemdata: [{ text:"TestA" }, { text:"TestB", submenu: { id:"test2", itemdata: [ {text:"TestB-1"},
      {text:"TestB-2", submenu: { id:"test3", itemdata:[ {text:"TestB-2-1"}, {text:"TestB-2-2"} ] } }] } } ] } },

      { text:"View", submenu: { id:"View", itemdata: [ { text:"item1" },{ text:"item2" }] } },
      { text:"Inserted", submenu: { id:"menuPlaceToInsert", itemdata: [ { id:"itemPlaceToInsert", text:"I will have a submenu" }] } }
      ];

      var submenuData =
      [
      { text:"Test", submenu: { id:"aTest", itemdata: [{ text:"TestA" }, { text:"TestB", submenu: { id:"atest2", itemdata: [ {text:"TestB-1"},
      {text:"TestB-2", submenu: { id:"atest3", itemdata:[ {text:"TestB-2-1"}, {text:"TestB-2-2"} ] } }] } } ] } }

      ];

      var titles = ["insertedItem1", "insertedItem2"];
      var oMenuBar;

      function menu_Show ( )
      {
      oMenuBar = new YAHOO.widget.MenuBar("myMenu", { itemdata: menuData });
      YAHOO.util.Dom.addClass(oMenuBar.element, "yuimenubarnav");
      oMenuBar.render ( "menuDiv" );

      var menuWhereToInsert = YAHOO.widget.MenuManager.getMenu("menuPlaceToInsert");
      }
      Array.prototype.add = function ( object )
      {
      this[this.length] = object;
      };

      YAHOO.util.Event.onDOMReady(menu_Show);

      var gDynamicMenuUniqueId = 0;
      var levelOneMenu = null;
      var insertCount = 0;

      function insertSubmenu( )
      {
      var itemWhereToInsert = YAHOO.widget.MenuManager.getMenuItem("itemPlaceToInsert");
      var existingSubMenu = itemWhereToInsert.cfg.getProperty ( "submenu" );

      if ( existingSubMenu != null )
      {
      deleteSubmenu ( existingSubMenu );// I wasn't sure if .clearContent() was `deep', but this does not seem to make any differenceÂ…
      existingSubMenu.clearContent();
      }

      itemWhereToInsert.cfg.setProperty("submenu", null );

      levelOneMenu = new YAHOO.widget.Menu("idlevelOneMenu");

      for ( var i = 0; i < 6; i++ )
      {
      var levelOneMenuItem = new YAHOO.widget.MenuItem ( "LevelOne_" + insertCount );
      levelOneMenu.addItem ( levelOneMenuItem );

      var levelTwoMenu = new YAHOO.widget.Menu("idSubMenu");

      for ( var j = 0; j < 6; j++ )
      {
      var levelTwoMenuItem = new YAHOO.widget.MenuItem ( "LevelTwo_" + insertCount );
      levelTwoMenu.addItem ( levelTwoMenuItem );

      levelThreeMenu = new YAHOO.widget.Menu("LevelThree_" + insertCount);

      for ( var k = 0; k < 6; k++ )
      {
      var id = "template" + gDynamicMenuUniqueId++;
      var valueObj = { foo1: 1, foo2: 2 };
      var item = { text: "LevelThree_" + insertCount, id: id, onclick: { fn: onClickItem }, value: valueObj };
      var realItem = levelThreeMenu.addItem ( item );
      }

      levelTwoMenuItem.cfg.setProperty ("submenu", levelThreeMenu );
      }

      levelOneMenuItem.cfg.setProperty ("submenu", levelTwoMenu );
      }

      var staticItem = { text:"Static Item", id:"staticItem", onclick: { fn: onClickItem } };
      levelOneMenu.addItem ( staticItem, 1 );

      itemWhereToInsert.cfg.setProperty("submenu", levelOneMenu );
      levelOneMenu.render ( itemWhereToInsert.element );

      var statusDiv = document.getElementById ( "statusDiv" );
      statusDiv.innerHTML = statusDiv.innerHTML + "<br/>" + "Insert submenu: " + insertCount;

      insertCount++;

      }

      function deleteSubmenu ( menu )
      {
      try
      {
      var aSubmenus = menu.getSubmenus();
      if ( aSubmenus )
      {
      for ( var i = 0; i < aSubmenus.length; i++ )
      {
      var submenu = aSubmenus[i];
      deleteSubmenu ( submenu );
      submenu.clearContent();
      }
      }

      this.deleteSubmenuToo ( menu );
      }
      catch ( e )
      {
      }
      }

      function deleteSubmenuToo ( menu )
      {
      try
      {
      var aItems = menu.getItems();
      for ( var i = 0; i < aItems.length; i++ )
      {
      var menuitem = aItems[i];
      if ( menuitem.value )
      {
      menuItemCount--;
      menuitem.value = null;
      }
      }
      }
      catch ( e )
      {
      }
      }

      function onClickItem ( eventType, args, objArg )
      {
      }

      var gTestCount = 25;

      function doLeakTest()
      {
      testTimer = setInterval(doLeakTestTimer, 5 * 1000);
      }

      function doLeakTestTimer()
      {
      insertSubmenu();

      gTestCount--;
      }

      function checkIfLeakTestDone()
      {
      if ( gTestCount == 0 )
      {
      clearInterval ( testTimer );
      alert ( "test done" );
      }
      }

      function stopLeakTest()
      {
      gTestCount = 0;
      checkIfLeakTestDone();
      }

      </script>
      <body class=" yui-skin-sam">
      "Insert Submenu" will insert submenu once. "Do Leak Test" will insert (and delete) submenu 25 times.
      <div id="menuDiv" height="20px"></div>
      <button onclick="insertSubmenu();">Insert Submenu</button>
      <button onclick="doLeakTest();">Do Leak Test</button>
      <button onclick="stopLeakTest();">Stop Leak Test</button>
      <div id="statusDiv"></div>
      </body>
      </html>
    Your message has been successfully submitted and would be delivered to recipients shortly.