1 Reply Latest reply on Feb 6, 2007 2:12 AM by Lacito_Domingo

    Possible memory leak in e4x or HTTPService with e4x format

    Lacito_Domingo
      Hello,

      I think I have found a memory leak in e4x.
      In very special cases (=xml) the player swallows the memory.

      The little test program connects to a web server for an xml file, and the result is converted to an array.
      The array is displayed in a DataGrid.

      There are two files:
      leaktest.xml doesn't leak in any cases (format: e4x or xml)
      pbentries.xml leaks when the format is e4x.

      Choose e4x format and check Use "Leak" file! Than the program leaks.

      For the whole test case (mxml file, html file and xml files) please contact me at

      lacito@contenet.hu

      or

      sas_laci@freemail.hu

      and I send a zip file as soon as possible.

      Probably there is a bug in my test program. If so than please send me a feedback.

      Thanks,

      Lacito

      ------ For the program cut here ------

      <?xml version="1.0" encoding="utf-8"?>
      <mx:Application xmlns:mx=" http://www.adobe.com/2006/mxml" layout="absolute">
      <mx:Script>
      <![CDATA[
      import mx.managers.PopUpManager;
      import mx.core.Application;
      import mx.controls.Alert;
      import mx.rpc.events.FaultEvent;
      import mx.rpc.events.ResultEvent;
      import mx.rpc.http.mxml.HTTPService;

      protected var records_:Array = null;

      protected var httpService:HTTPService = null;

      [Bindable("recordsChange")]
      public function set records(_records:Array):void
      {
      this.records_ = _records;
      var e:Event = new Event("recordsChange");
      dispatchEvent(e);
      }

      public function get records():Array
      {
      return records_;
      }


      protected function getXML():void
      {
      var resultFormat:String = cbResultFormat.selectedItem as String;
      var params:Object = new Object();
      httpService = new HTTPService();
      httpService.concurrency = "single";
      httpService.showBusyCursor = true;
      var lastIndex:int = url.lastIndexOf("/");
      var fileName:String = null;
      if(chbUseLeakFile.selected)
      {
      // It leaks... :(
      fileName = "pbentries.xml";
      }
      else
      {
      // It doesn't leak... :)
      fileName = "leaktest.xml";
      }
      var _url:String = url.substr(0, lastIndex+1) + fileName;
      httpService.url = _url;
      httpService.resultFormat = resultFormat;
      httpService.method = "POST";
      httpService.addEventListener(ResultEvent.RESULT, processResult);
      httpService.addEventListener(FaultEvent.FAULT, processFault);
      httpService.send(params);
      }

      protected function processResult(e:ResultEvent):void
      {
      var resultFormat:String = cbResultFormat.selectedItem as String;
      removeListeners();
      if(resultFormat==mx.rpc.http.HTTPService.RESULT_FORMAT_XML)
      {
      setArrayFromXMLNode();
      }
      else
      {
      setArrayFromXML();
      }
      destroyHttpService();
      }

      // format= "e4x"
      protected function setArrayFromXML():void
      {
      var xml_:XML = httpService.lastResult as XML;
      var ar:Array = new Array();
      var x:XML = null;
      var xl:XMLList = xml_.phonebookEntries[0].phonebookEntry;
      for each(x in xl)
      {
      var record:Object = new Object();
      var prop:XML = null;
      var props:XMLList = x.children();
      for each(prop in props)
      {
      record[prop.localName()] = prop.toString();
      }
      ar.push(record);
      }
      records = ar;
      }

      // format= "xml"
      protected function setArrayFromXMLNode():void
      {
      var xml_:XMLNode = httpService.lastResult as XMLNode;
      var ar:Array = new Array();
      var x:XMLNode = null;
      var xl:Array = xml_.lastChild.childNodes;
      for each(x in xl)
      {
      var record:Object = new Object();
      var prop:XMLNode = null;
      var props:Array = x.childNodes;
      for each(prop in props)
      {
      record[prop.localName] = prop.firstChild!=null ? prop.firstChild.nodeValue : null;
      }
      ar.push(record);
      }
      records = ar;
      }

      protected function destroyHttpService():void
      {
      httpService.clearResult(false);
      httpService.disconnect();
      httpService = null;
      }

      protected function processFault(e:FaultEvent):void
      {
      removeListeners();
      Alert.show(e.fault.faultString, e.fault.faultCode);
      destroyHttpService();
      }

      protected function removeListeners():void
      {
      httpService.removeEventListener(ResultEvent.RESULT, processResult);
      httpService.removeEventListener(FaultEvent.FAULT, processFault);
      }

      protected function collect():void
      {
      // Garbage Collection
      try
      {
      new LocalConnection().connect('foo');
      new LocalConnection().connect('foo');
      }
      catch(e:*)
      {
      }
      }
      ]]>
      </mx:Script>
      <mx:ArrayCollection id="alRecords" source="{records}" />
      <mx:Label x="10" y="10" text="Result format:" id="lResultFormat"/>
      <mx:ComboBox x="104" y="8" id="cbResultFormat">
      <mx:Array>
      <mx:String>e4x</mx:String>
      <mx:String>xml</mx:String>
      </mx:Array>
      </mx:ComboBox>
      <mx:DataGrid id="dgRecords" x="10" y="36" width="936" height="437"
      dataProvider="{alRecords}"
      verticalScrollPolicy="auto" horizontalScrollPolicy="auto">
      </mx:DataGrid>
      <mx:Button x="355" y="496" label="Get xml" id="btnGetXML" click="{getXML();}" />
      <mx:Button x="155" y="496" label="GC" id="btnGC" click="{collect();}" />
      <mx:CheckBox x="276" y="10" label="Use &quot;LEAK&quot; file:" labelPlacement="left" id="chbUseLeakFile" selected="true"/>
      </mx:Application>