2012-03-16 49 views
0

我有a Flex 4.6 web game,它顯示2個帶有2個自定義項目渲染器的虛擬佈局的列表。渲染器主要由顯示用戶頭像和少量標籤的BitmapImages組成。在Flex 4.6 Web應用程序中找不到巨大的內存泄漏

enter image description here

的名單正在通過用gzip壓縮JSON數據TCP套接字經常更新。 I merge that data into 2 ArrayCollections充當列表的數據提供者。這似乎工作得很好,列表不閃爍並且正確更新(我已經監視了很多調試跟蹤信息)。

{ 
    lobby: [ 
     "OK252342810632", 
     "OK122471020773", 
     "DE54", 
     "DE6577", 
     "DE7981", 
     "OK225312168135", 
     "OK20629248715", 
     "DE7880", 
    ], 
    games: [ 
     { 0: [] }, 
     { 9012: [ 
      "VK48058967", 
      "MR14315189992643135976", 
      "OK10218913103", 
     ] }, 
     { 9013: [ 
      "OK305894249541", 
      "OK151358069597", 
      "OK515549948434", 
     ] }, 
     { 9007: [ 
      "OK366541092321", 
      "DE7062", 
      "OK122700338897", 
     ] }, 
     { 8993: [ 
      "OK78476527766", 
      "VK5692120" 
     ] } 
    ] 
} 

我的問題是,應用程序很快就會遲緩,對於一些用戶來說插件崩潰,所以用戶抱怨很多。

在我看到這幅畫的輪廓(跳轉到內存20 MB,並在那裏停留,有時跳轉到40MB等):

enter image description here

從探查我想不通 - 什麼是泄漏記憶。在頂部,我看到矢量。 < *>類別 - 無論如何。

我試過這麼多的事情已經解決這個問題:

  • 從本地JSON.parse()來回到com.brokenfunction.json.decodeJson()(因爲我想,也許得到的Adobe交換這是錯誤的)

    • 我刪除了JSON對象,我分析後:

    私有函數handleTcpData(事件:ProgressEvent):無效{ //讀取ByteArray的插座上,將它解壓縮 - 行之有效

    var obj:Object = decodeJson(_bytes.toString()); 
    
    // merge into 2 ArrayCollections, update GUI... works well? 
    
    for (var key:String in obj) 
        delete obj[key]; 
    obj = null; 
    

    }

    • 我已經關掉ContentCache關閉 - 沒有什麼區別

    • 我使用任何臨時停止。對象,如{ID: 「DE22」},並使用JSON對象直接

是否有人請有好的建議?

我讀過很多關於AS3垃圾收集和常用技巧的文檔/博客:將對象引用設置爲null,使用弱事件偵聽器,removeChild()不釋放內存等 - 但我沒有看看如何將這個應用到我的問題。

以下是我的完整大堂。MXML源代碼:

<?xml version="1.0" encoding="utf-8"?> 
<s:Group 
    xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:comps="*" 
    width="700" height="450"> 

    <fx:Declarations> 
     <s:RadioButtonGroup id="_filter" change="handleRadio(event);" /> 
    </fx:Declarations> 

    <fx:Metadata> 
     [Event(name="game", type="PrefEvent")] 
    </fx:Metadata> 

    <fx:Script> 
     <![CDATA[ 
      import mx.collections.ArrayCollection; 
      import mx.utils.ObjectUtil; 

      [Bindable] 
      private var _games:ArrayCollection = new ArrayCollection(); 
      [Bindable] 
      private var _users:ArrayCollection = new ArrayCollection(); 

      private function handleRadio(event:Event):void { 
       switch (_filter.selection) { 
        case _allBtn: 
         _games.filterFunction = null; 
         break; 
        case _vacBtn: 
         _games.filterFunction = vacantGame; 
         break; 
        case _fullBtn: 
         _games.filterFunction = fullGame; 
         break; 
       } 
       _games.refresh(); 
      } 

      private function vacantGame(obj:Object):Boolean { 
       for (var id:String in obj) { 
        var players:Array = obj[id]; 
        return players.length < 3; 
       } 

       return false; 
      } 

      private function fullGame(obj:Object):Boolean { 
       for (var id:String in obj) { 
        var players:Array = obj[id]; 
        return players.length == 3; 
       } 

       return false; 
      } 

      // merge arrays of objects 
      private function mergeObjs(ac:ArrayCollection, array:Array):void { 
       var i:int; 
       var j:int; 
       var n:int; 
       var src:Array = ac.source; 

       // 1) remove items missing in data from _data 
       FOUND1: 
       for (i = src.length - 1; i >= 0; i--) { 
        for (j = array.length - 1; j >= 0; j--) { 
         if (ObjectUtil.compare(src[i], array[j]) == 0) 
          continue FOUND1; 
        } 

        n = ac.getItemIndex(src[i]); 
        if (Util.DEBUG) 
         trace('REMOVED OBJ ' + src[i] + ' filtered n=' + n + ' i=' + i); 

        // remove visible items 
        if (n > -1) 
         ac.removeItemAt(n); 
        // remove hidden (filtered) items 
        else 
         src.splice(i, 1); 
       } 


       // 3) add items appeared in data to _data 
       FOUND2: 
       for (j = 0; j < array.length; j++) { 
        for (i = 0; i < src.length; i++) { 
         if (ObjectUtil.compare(src[i], array[j]) == 0) 
          continue FOUND2; 
        } 

        if (Util.DEBUG) 
         trace('ADDED OBJ ' + array[j] + ' i=' + i); 

        //ac.addItemAt(array[j], i); 
        ac.addItem(array[j]); 
       } 
      } 

      // merge arrays of strings (the user ids) 
      private function mergeIds(ac:ArrayCollection, array:Array):void { 
       var i:int; 
       var j:int; 
       var n:int; 
       var src:Array = ac.source; 

       // 1) remove items missing in data from _data 
       FOUND1: 
       for (i = src.length - 1; i >= 0; i--) { 
        for (j = array.length - 1; j >= 0; j--) { 
         if (i == j) 
          continue FOUND1; 
        } 

        n = ac.getItemIndex(src[i]); 
        if (Util.DEBUG) 
         trace('REMOVED ID ' + src[i] + ' filtered n=' + n + ' i=' + i); 

        // remove visible items 
        if (n > -1) 
         ac.removeItemAt(n); 
         // remove hidden (filtered) items 
        else 
         src.splice(i, 1); 
       } 


       // 3) add items appeared in data to _data 
       FOUND2: 
       for (j = 0; j < array.length; j++) { 
        for (i = 0; i < src.length; i++) { 
         if (i == j) 
          continue FOUND2; 
        } 

        if (Util.DEBUG) 
         trace('ADDED ID ' + array[j] + ' i=' + i); 

        ac.addItem(array[j]); 
       } 
      } 

      public function update(games:Array, lobby:Array):void { 
       var vac:uint = 0; 
       var full:uint = 0; 

       for each (var game:Object in games) { 
        for (var id:String in game) { 
         var players:Array = game[id]; 
         if (!players) 
          continue; 

         if (players.length < 3) 
          vac++; 
         else if (players.length == 3) 
          full++; 
        } 
       } 

       if (games) 
        mergeObjs(_games, games); 

       if (lobby) 
        mergeIds(_users, lobby);  

       _allBtn.label = 'All ' + _games.source.length; 
       _vacBtn.label = 'Vacant ' + vac; 
       _fullBtn.label = 'Full ' + full; 
      } 

      public function appendText(str:String):void { 
       _chat.appendText(str); 
      } 
     ]]> 
    </fx:Script> 

    <s:VGroup width="100%" height="100%"> 
     <s:HGroup width="100%" verticalAlign="baseline" paddingLeft="8" paddingRight="8"> 
      <s:Label text="Игровые столы:" /> 
      <s:RadioButton id="_allBtn" group="{_filter}" label="Все" selected="true" /> 
      <s:RadioButton id="_vacBtn" group="{_filter}" label="Свободные" /> 
      <s:RadioButton id="_fullBtn" group="{_filter}" label="Полные" /> 
      <s:Spacer width="100%" /> 
      <s:Label text="Игроки в лобби: {_users.length}" /> 
     </s:HGroup> 

     <mx:HDividedBox width="100%" height="100%"> 
      <s:List id="_gamesList" itemRenderer="Game" useVirtualLayout="true" dataProvider="{_games}" skinClass="PrefListSkin" width="100%" height="100%" minWidth="180"> 
       <s:layout> 
        <s:TileLayout /> 
       </s:layout> 
      </s:List> 

      <mx:VDividedBox width="180" height="100%" minWidth="180"> 
       <s:List id="_usersList" itemRenderer="User" useVirtualLayout="true" dataProvider="{_users}" skinClass="PrefListSkin" width="100%" height="100%" minHeight="150"> 
        <s:layout> 
         <s:TileLayout /> 
        </s:layout> 
       </s:List> 
       <s:TextArea id="_chat" width="100%" height="100%" minHeight="40" editable="false" fontSize="14" color="#000000" horizontalScrollPolicy="off"/> 
      </mx:VDividedBox> 
     </mx:HDividedBox> 

    </s:VGroup> 
</s:Group> 

UPDATE:

我必須補充一點,我從XML轉換成JSON後,我的問題(用戶抱怨可再現的Flash插件崩潰)已經開始。

我已經重新運行探查和爲什麼它顯示JSON.parseCore 987個實例,同時也有400只在大堂用戶(只有極少數目前正在與虛擬佈局的列表可見)?

enter image description here

任何想法請,當我從XML去JSON什麼可能有哪些變化? (我沒有碰別人)。我實際上希望獲得更好的性能,因爲我有時會閱讀有關Flex中XML泄漏內存的問題...

+1

在這一點上,我會嘗試兩件事情。 1消除/減少,即一次刪除應用程序的塊,並根據扣除情況查看導致內存泄漏的操作。 2創建或使用現有的記錄器類,記錄每個函數開始和結束時的執行時間和日誌消息,並輸出總內存。 http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/system/System.html#totalMemory – shaunhusain 2012-03-16 16:52:32

+1

在這裏查看util包,我發佈了一個記錄器,它可以完成我在上面解釋的http:// www.shaunhusain.com/DrawTextRandomly/srcview/ – shaunhusain 2012-03-16 16:52:53

+2

也作爲cupuyc表示,這似乎不是一個內存泄漏給我,我期望在剖析器中看到一致的上升線,如果它,而是我只看到尖峯當一些東西被加載,然後一條扁平線表示內存是穩定的。 – shaunhusain 2012-03-16 17:00:04

回答

2

您的代碼和功能看起來非常簡單。我不認爲內存泄漏是這種情況。你能夠自己再現「呆滯」嗎?

我注意到你有聊天。如果會有很多文本 - 應用程序可能會在某個時刻緩慢並崩潰。請務必限制聊天,以僅顯示最後100行。

更新: 剛剛訪問過您的遊戲,並注意到用戶具有高分辨率圖像作爲配置文件圖像。隨着人數的增長,它可能會導致緩慢。

+1

是的,玩家使用相當高分辨率的頭像/照片......我想知道如何提高性能 - 我不想在飛行中創建任何小的位圖 - 因爲我的遊戲可以在全屏模式下運行。 – 2012-03-16 17:04:25

+1

您可以嘗試禁用這些圖像並檢查遊戲是否運行得更好。 – 2012-03-16 17:06:04