ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

android – SQL Cursor在调用getString时抛出内存不足

2019-07-08 15:26:03  阅读:320  来源: 互联网

标签:android out-of-memory sqlcipher xml-deserialization


附件参考我之前的问题: – Out of memory

我会尽量保持精确.我从我的web服务调用得到一个长base64字符串的响应.我解码字符串并得到一个包含我的数据的巨大字符串.我反序列化字符串并使用如下字符串创建我的类的对象.

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

desrialiseGame()只是一种解析数据并创建和返回我的游戏实例的方法.为了将这个对象保持为多个会话(登录/注销),我将我的整个gameData(我的字符串,其反序列化给了我的游戏实例)存储在数据库中.

下次用户登录时,为了创建Game实例,我从我的DB中获取字符串,然后再次尝试反序列化,以便我回到我的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));我内存不足错误.根据我的发现,当我在应用程序标记的清单中添加标志largeHeap = true时,我的应用程序变得非常缓慢.还有developer.android声明

Never request a large heap simply because you’ve run out of memory
and you need a quick fix—you should use it only when you know exactly
where all your memory is being allocated and why it must be retained.
Yet, even when you’re confident your app can justify the large heap,
you should avoid requesting it to whatever extent possible.

任何人都可以建议我如何避免这种情况.大多数SO问题都没有位图使用.任何帮助将不胜感激.

解决方法:

SQLCipher for Android为每个光标窗口分配一个内存缓冲区,最大大小为1 MB.由于您评论说游戏数据文件非常大,因此大小可能超过了光标窗口的最大大小,从而导致内存分配错误.在这种情况下,我们可能会推荐以下两个选项之一:

>将游戏数据规范化为更典型的数据库结构(即多个表,列,行).
>将游戏数据文件拆分成片段,每个片段小于1 MB,然后在应用程序中重新组合它们.

标签:android,out-of-memory,sqlcipher,xml-deserialization
来源: https://codeday.me/bug/20190708/1403468.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有