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 行あるため、必要に応じてトレースを消去する必要があります。プロファイリングのおかげで見つかった 2 つの問題があります

  1. メソッド updateXMLC で httpS.send() が呼び出されるたびに、URLLoader が内部的に呼び出され、不要になった XML がガベージ コレクションされることなくメモリ内をさまよっています。
  2. xmlC を更新するより効果的な方法はありますか? XMLListCollection が更新されるたびに、XMLListCollection の以前の値がガベージ コレクションされないようです。
4

4 に答える 4

4

コードを見て、メモリリークが発生するのではないかと懐疑的で興味をそそられたので、自分でコードをテストしました。

投稿したコードは実際には実行できません。app tagや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

XML の要求、受信、および処理にかかる時間は? かなり大きなファイルのように聞こえるので、1 秒を超える場合は、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
    {
        httpsS.url = "data.xml";
        httpS.addEventListener(ResultEvent.RESULT, resultHTTP);
        httpsS.resultFormat="e4x";

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

    プライベート関数 updateXMLC(event:TimerEvent):void
    {
        timer.stop();
        httpS.send();
    }

    プライベート関数 resultHTTP(event:ResultEvent):void
    {
        xmlData = XML としての event.result;
        xmlC.source = xmlData.dg.rows.row;
        timer.start();
    }

問題を誤解していたら申し訳ありませんが...

いずれにせよ、ある種の faultHTTP 関数も同様に配置したいので、HTTP エラー時にタイマーを再起動します (または、必要なことをすべて行います)。

于 2012-07-10T14:57:10.597 に答える
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 に答える