0

我有以下代码:

private var xmlC:XMLListCollection = new XMLListCollection();
private var httpS:HTTPService = new HTTPService();
private var timer:Timer = new Timer(1000);
private var xmlData:XML;
private var xmlDataList:XMLList;

protected function application1_creationCompleteHandler(event:FlexEvent):void
{
    httpS.url = "data.xml";
    httpS.addEventListener(ResultEvent.RESULT, resultHTTP);
    httpS.resultFormat="e4x";
    httpS.send();

    timer.start();
    timer.addEventListener(TimerEvent.TIMER, updateXMLC);
}

private function updateXMLC(event:TimerEvent):void
{
    xmlC.source = xmlDataList;
    httpS.send();
}

private function resultHTTP(event:ResultEvent):void
{
    xmlData = event.result as XML;
    xmlDataList = xmlData.dg.rows.row;
}

“data.xml”有 5000 行,所以我需要在必要时清理它的痕迹。由于分析,我发现了两个问题

  1. 每次在方法 updateXMLC 中调用 httpS.send() 时,它都会在内部调用 URLLoader,从而使不再需要的 XML 在内存中徘徊而不会被垃圾收集
  2. 有没有更有效的方法来更新 xmlC,每当更新 XMLListCollection 时,似乎 XMLListCollection 的先前值不会被垃圾收集
4

4 回答 4

4

在查看代码后我怀疑/好奇会有任何内存泄漏,所以我自己测试了你的代码。

您发布的代码实际上无法运行。我刚刚添加了最低限度,让它像 app 标签和 import 语句一样运行(以及一个计数器标签,用于查看 http 服务周期何时完成):

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="application1_creationCompleteHandler(event)"> 
<mx:Script>
    <![CDATA[
        import mx.rpc.http.HTTPService;
        import mx.collections.XMLListCollection;
        import mx.rpc.events.ResultEvent;
        import mx.events.FlexEvent;

        private var xmlC:XMLListCollection = new XMLListCollection();
        private var httpS:HTTPService = new HTTPService();
        private var timer:Timer = new Timer(1000);
        private var xmlData:XML;
        private var xmlDataList:XMLList;

        protected function application1_creationCompleteHandler(event:FlexEvent):void
        {
            httpS.url = "data.xml";
            httpS.addEventListener(ResultEvent.RESULT, resultHTTP);
            httpS.resultFormat="e4x";
            httpS.send();

            timer.start();
            timer.addEventListener(TimerEvent.TIMER, updateXMLC);
        }

        private function updateXMLC(event:TimerEvent):void
        {
            xmlC.source = xmlDataList;
            httpS.send();
        }

        private function resultHTTP(event:ResultEvent):void
        {
            counter.text = Number(parseInt(counter.text,10)+1).toString(); 
            xmlData = event.result as XML;
            xmlDataList = xmlData.dg.rows.row;
        }
    ]]>
</mx:Script>
<mx:Label id="counter" text="0" horizontalCenter="0" verticalCenter="0" fontSize="72"/>
</mx:Application>

好消息是您的代码中没有任何内存泄漏。探查器中也没有任何游荡对象。

坏消息是您在应用程序中所做的任何其他事情(代码未在此处发布,无论出于何种原因省略) - 这就是您有泄漏/游荡对象的地方。

您可以在附加代码的分析器中亲自看到,在 http 服务的前几个周期后内存没有增加。即它不会随着时间的推移继续掌握更多的记忆。(顺便说一下,我要提取的 XML 文件大约有 8000 行,超过 1MB)。

如果您想发布更多代码,很乐意进一步查看 - 但现在认为这解决了这个谜团。;)

以下是您所做的一些修复:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="application1_creationCompleteHandler(event)">
<mx:Script>
    <![CDATA[
        import mx.rpc.http.HTTPService;
        import mx.collections.XMLListCollection;
        import mx.rpc.events.ResultEvent;
        import mx.events.FlexEvent;

        [Bindable] private var xmlC:XMLListCollection = new XMLListCollection();
        private var httpS:HTTPService = new HTTPService();
        private var timer:Timer = new Timer(1000);
        private var xmlData:XML;
        private var xmlDataList:XMLList;
        private var serviceRunning : Boolean = false;
        private var currentData : String = '';

        protected function application1_creationCompleteHandler(event:FlexEvent):void
        {
            httpS.url = "data.xml";
            httpS.addEventListener(ResultEvent.RESULT, resultHTTP);
            httpS.resultFormat="e4x";
            httpS.send();

            timer.start();
            timer.addEventListener(TimerEvent.TIMER, updateXMLC);
        }

        private function updateXMLC(event:TimerEvent):void
        {
            xmlC.source = xmlDataList;
            if( !serviceRunning ){  // don't call for more data until 
                httpS.send();       // you've gotten back last call
            }
        }

        private function resultHTTP(event:ResultEvent):void
        {
            // make sure we have differences before rebinding
            var newData : String = event.result as String;
            serviceRunning = false;
            counter.text = Number(parseInt(counter.text,10)+1).toString();
            if( newData !=  currentData ){
                xmlData = event.result as XML;
                currentData = newData;
                xmlDataList = xmlData.dg.rows.row;
            }
        }
    ]]>
</mx:Script>
<mx:Label id="counter" text="0" horizontalCenter="0" verticalCenter="0" fontSize="72"/>
 </mx:Application>
于 2012-07-10T22:02:00.270 回答
0

如果我正确理解您的代码,则您正在从与您的 SWF 位于同一文件夹中的文件中恢复您的 XML 数据。如果是这种情况,那么最有可能发生的是 XML 文件被缓存在您的浏览器中,并且它一遍又一遍地返回相同的缓存版本。

在处理这些问题时,您可以添加一个虚拟 URL 变量,使浏览器认为您正在检索的文件是新的,并强制它再次恢复该文件。

您可以通过执行以下操作来实现此目的:

httpS.url = "data.xml?random="+Math.floor(Math.random()*1000);

如果这不能解决问题,那么它可能与不重置保存实际 XML 数据的变量有关。您可以通过重置变量的新实例来完成此操作:

xmlData = new XML();
xmlDataList = new XMLList();
xmlC = new XMLListCollection();

或者,如果您只想重置 XMLListCollection,您可以尝试使用 Flex 中所有列表中包含的“refresh()”方法。

重要提示:如果您使用数据绑定与这些变量中的任何一个,这可能会导致 Flex 不会垃圾收集数据,因为它正在某处使用。

于 2012-07-09T20:45:48.360 回答
0

请求、接收和处理 XML 需要多长时间?听起来它是一个相当大的文件,所以如果超过一秒钟,您将同时发生对 HTTPService 的多次调用(据我了解,您当前的计时器将尝试每秒触发一次请求,无论是否最后一个已经返回)。

我不确定这是否是您想要的,但我对此表示怀疑。如果我是对的,并且您只想在获得最后一个响应后发送请求,那么您最好摆脱计时器及其功能,然后将 resultHTTP 方法更改为类似这:

private function resultHTTP(event:ResultEvent):void
{
    xmlData = event.result as XML;
    xmlC.source = xmlData.dg.rows.row;
    httpS.send();
}

当然,您可能希望每次开始都延迟它:

    受保护的函数 application1_creationCompleteHandler(event:FlexEvent):void
    {
        httpS.url = "data.xml";
        httpS.addEventListener(ResultEvent.RESULT, resultHTTP);
        httpS.resultFormat="e4x";

        计时器.start();
        timer.addEventListener(TimerEvent.TIMER, updateXMLC);
    }

    私有函数 updateXMLC(event:TimerEvent):void
    {
        计时器.stop();
        httpS.send();
    }

    私有函数 resultHTTP(event:ResultEvent):void
    {
        xmlData = event.result 作为 XML;
        xmlC.source = xmlData.dg.rows.row;
        计时器.start();
    }

对不起,如果我误解了这个问题......

无论哪种方式,您可能还想放入某种 faultHTTP 函数,因此它还会在 HTTP 错误时重新启动计时器(或执行您需要做的任何事情)。

于 2012-07-10T14:57:10.597 回答