2014-09-22 54 views
4

附件參考我先前的問題: - Out of memorySQL遊標引發內存,同時呼籲的getString

我會嘗試儘可能精確。我從我的web服務調用中獲得一個長base64字符串的響應。我解碼字符串並獲得一個包含我的數據的巨大字符串。我反序列化字符串並使用下面的字符串創建我的類的對象。

String decryptedXml = XmlObject.toDecryptedXmlString(gameDetail.getGameData(), app.getSessionEncryptionKey()); 
Game noviceGame = deserialiseGame(decryptedXml, NoviceGamer.class); 

desrialiseGame()只是一個方法,它對數據進行反序列化並創建並返回我的遊戲實例。爲了將這個對象維護到多個會話(登錄/註銷),我在數據庫中存儲了我的整個gameData(我的字符串,其反序列化給了我的Game實例)。

下一次用戶登錄時,要創建Game實例,我從我的數據庫中獲取字符串,然後再次嘗試去序列化,以便返回我的Game實例。但是當我試圖從我的數據庫中獲取字符串時,在獲取字符串時出現'OUT OF MEMORY'異常。

調用以反序列化遊戲的方法如下。

private HashMap<String, Game> games = new HashMap<String, Game>(); 

public void load(LocalDatabaseHelper localDbHelper) throws Exception 
{ 
    synchronized(gameLockObject) { 
     GameDetailDAO dao = new GameDetailDAO(localDbHelper); 

     //this will fetch me the all the entities from databse 
     ArrayList<GameDetailEntity> dbGameDetails = dao.getEntities(null, null); 

     for (GameDetailEntity gameDetail : dbGameDetails) { 
      String gameLevel = gameDetail.getDetailLevel();    

      String gameXml = gameDetail.getGameData(); 

      Game game = null; 
      if(gameLevel.equalsIgnoreCase("Novice")) { 
       game = Job.deserialiseJob(gameXml, NoviceLevel.class); 
      } 
      else if (gameLevel.equalsIgnoreCase("Expert")) { 
       game = Job.deserialiseJob(gameXml, ExpertLevel.class); 
      } 

      //set the job version 
      game.setGameversion(gameDetail.getGameVersion()); 
      game.setMagicNumber(gameDetail.getMagicNumber()); 
      game.setInactiveUser(gameDetail.getInactiveUser()); 
      game.setStartTime(gameDetail.getStartTime()); 
      game.setFinishTime(gameDetail.getFinishTime()); 
      game.setGameCompletionTime(gameDetail.getGameCompletionTime()); 
      if (!StringUtils.isNullOrEmpty(gameDetail.getGameStatus())) { 
       game.setGameStatus(GameStatus.valueOf(gameDetail.getGameStatus())); 
      } 

      //add the job to the store 
      games.put(gameDetail.getGameRef().toLowerCase(Locale.getDefault()), game); 
     } 
    } 
} 

我的數據庫事務如下:

@Override 
    protected GameEntity getEntityFromCursor(Cursor cursor) 
    { 
     String gameRef = cursor.getString(cursor.getColumnIndex(GAME_REF)); 
     String detailLevel = cursor.getString(cursor.getColumnIndex(DETAIL_LEVEL)); 
     int gameVersion = cursor.getInt(cursor.getColumnIndex(GAME_VERSION)); 
     String gameData = cursor.getString(cursor.getColumnIndex(GAME_DATA)); 
     String status = cursor.getString(cursor.getColumnIndex(GAME_STATUS)); 

     long longStart = cursor.getLong(cursor.getColumnIndex(VISIT_START_TIME)); 
     Date startTime = longStart == -1 ? null : new Date(longStart); 

     long longFinish = cursor.getLong(cursor.getColumnIndex(VISIT_END_TIME)); 
     Date finishTime = longFinish == -1 ? null : new Date(longFinish); 

     long longComplete = cursor.getLong(cursor.getColumnIndex(GAME_COMPLETION_TIME)); 
     Date completionTime = longComplete == -1 ? null : new Date(longComplete); 

     GameEntity entity = new GameEntity(gameRef, detailLevel, gameVersion, gameData,); 
     entity.setGameStatus(status); 
     entity.setStartTime(startTime); 
     entity.setFinishTime(finishTime); 
     entity.setGameCompletionTime(completionTime); 
     return entity; 
    } 

但是當我嘗試從數據庫@Line String gameData = cursor.getString(cursor.getColumnIndex(GAME_DATA));獲取數據,我得到了內存不足的錯誤。根據我的發現,當我在應用程序標籤清單中添加flag largeHeap = true時,我的應用程序變得非常緩慢。而且還developer.android狀態

從未要求僅僅是因爲你已經用完了內存 一大堆,你需要速戰速決,你應該使用它,只有當你確切地知道 您所有的內存被分配和爲什麼必須保留。 然而,即使你確信你的應用程序可以證明大堆, 你應該避免在任何可能的範圍內請求它。

任何人都可以建議我如何避免這種情況。大多數SO問題都沒有使用位圖。任何幫助將不勝感激。

+0

您爲遊戲數據列存儲的數據有多大? – 2014-09-23 16:40:31

+0

不幸的是它相當大。 – Android 2014-09-24 04:57:48

回答

0

我遇到了問題,原因很簡單,字符串的大小很大。巨大。所以我決定減少字符串的大小。我已經從XML分離出圖像數據並存儲在不同的表格中。這減少了需要反序列化的數據量。我分別重新加載額外的數據。感謝您的寶貴時間和答案。

1

SQLCipher for Android爲每個遊標窗口分配一個內存緩衝區,最大大小爲1 MB。由於您評論說遊戲數據文件非常大,因此大小可能會超過遊標窗口的最大大小,從而導致內存分配錯誤。在這種情況下,我們可能會推薦以下兩種選擇之一:

  1. 將遊戲數據標準化爲更典型的數據庫結構(即多個表,列,行)。
  2. 將遊戲數據文件拆分爲片段,每個片段小於1 MB,然後在應用程序中重新組裝它們。