Android:文件阅读 - OutOfMemory问题

时间:2013-02-08 00:20:33

标签: android android-assets android-memory

我正在创建一个涉及从文件中读取数据的应用。该文件相对较大(1.8 MB),正在从onCreate中的异步线程中读取。应用程序第一次启动时,它加载得很好。但是,如果单击后退按钮然后再次加载它,它将耗尽内存并崩溃(抛出OutOfMemory错误)。

如何使用尽可能少的内存和/或释放内存?

文件读取代码(在异步类的doInBackground()方法中执行):

public ArrayList<String> createDataList() {
    dataList = new ArrayList<String>();
    BufferedReader br = null;
    try {
        br = new BufferedReader(new InputStreamReader(getAssets().open(
                    "text.txt")));
        String data;
        while ((data = br.readLine()) != null) {
            dataList.add(data);
        }                           
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            br.close(); // stop reading
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    return dataList;
}

编辑* 异步类:

private class loadData extends AsyncTask<Void, Void, ArrayList<String>> {

    @Override
    protected ArrayList<String> doInBackground(Void... arg0) {
        dataList = createDataList();
        return dataList;
    }

    protected void onPostExecute(ArrayList<String> result) {
        super.onPostExecute(result);
        // display first element in ArrayList in TextView as a test

    }

}

我尝试根据我想要组织数据的方式拆分文件,并将每个文本文件中的数据存储到单独的ArrayList中,但我也遇到了内存问题。我还将所有数据存储到一个“master”ArrayList中,然后在该“master”上调用一个方法将数据添加到相应的ArrayList(从“master”中删除/清除数据“一旦它复制了)。

有关如何简化和减少内存影响的任何想法?

编辑**

logcat的:

enter image description here

从您单击后退按钮然后再次加载活动时开始。以下只是生成的消息之一(详细):

enter image description here

3 个答案:

答案 0 :(得分:0)

您可以尝试在清单中添加android:largeHeap="true",但Android API-8不支持此功能。据我所知,您正在读取数据并将其存储到堆内存中,这通常非常有限,其大小取决于您运行应用程序的设备。

您可能还想在此进行调查:android - out of memory

答案 1 :(得分:0)

首先,确保内存中没有两份数据副本。在开始创建新ArrayList之前,您可以将对旧ArrayList的引用置空,尽管您必须小心谨慎 - 首先调用ArrayList.clear()会更彻底。

其次,使用hprof或Eclipse MAT等工具计算出ArrayList占用的内存量。如果它使用大量空间,您可能需要考虑更紧凑的数据表示。

所以......从代码片段看,你看起来只是在文件中读取一堆文本字符串,使用字节到字符的转换。如果源材料是纯UTF-8(即基本上是ASCII),那么你有一个2x扩展到UTF-16,加上char []对象的分配来保存它,再加上包装它的String对象的大小,加上ArrayList中条目的开销。根据文件中平均字符串的长度,这可能是1.8MB的重要倍数。

避免这种情况的一种方法是将文件作为byte[]读入内存,扫描它以确定每个字符串的起始位置,并保留每个字符串的起始偏移量的整数数组。当您需要字符串N时,将其从byte[]解码为String并将其返回。这显着降低了您的开销。您可以通过不加载文件并根据需要读取单个字符串(使用RandomAccessFile)来进一步减少它,但这可能会减慢速度。

答案 2 :(得分:0)

似乎你可能在immutability of Strings上遇到一些麻烦。

为什么不尝试更改代码,以便使用StringBuilder?当然,你必须改变不止一件事,但它与你的代码相似,并不会让你的记忆快速增加。