1

我正在创建一个涉及从文件中读取数据的应用程序。该文件相对较大 (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但我也遇到了内存问题。我还将所有数据存储到一个“主”ArrayList中,然后在该“主”上调用一个方法将数据添加到适当的位置ArrayList(一旦复制,就从“主”中删除/清除数据)。

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

编辑**

日志猫:

在此处输入图像描述

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

在此处输入图像描述

4

3 回答 3

1

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

您可能还想在这里调查:android - 内存不足

于 2013-02-08T00:35:15.730 回答
0

首先,确保内存中没有数据的两个副本。您可以在开始创建新的 ArrayList 之前取消对旧 ArrayList 的引用,尽管您必须小心地执行此操作——ArrayList.clear()首先调用会更彻底。

hprof其次,通过使用Eclipse MAT之类的工具来确定 ArrayList 占用了多少内存。如果它使用大量空间,您可能需要考虑更紧凑的数据表示。

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

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

于 2013-02-08T02:04:47.357 回答
0

似乎您可能对 Strings 的不变性有些麻烦。

为什么不尝试更改代码以便使用 StringBuilder ?当然,您必须更改不止一件事,但它与您的代码足够相似,并且不会很快填满您的内存。

于 2013-02-08T02:59:15.927 回答