Android:文件读取-内存溢出问题

Android:文件读取-内存溢出问题,android,android-assets,android-memory,Android,Android Assets,Android Memory,我正在创建一个应用程序,涉及从文件中读取数据。该文件相对较大(1.8 MB),正在onCreate中从异步线程读取。第一次启动应用程序时,它的加载情况很好。但是,如果单击“上一步”按钮,然后再次加载,它将耗尽内存并崩溃(抛出OutOfMemory错误) 我如何让它使用尽可能少的内存和/或在完成时释放内存 文件读取代码(在异步类的doInBackground()方法中执行): public ArrayList createDataList(){ dataList=newarraylist(); B

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

我如何让它使用尽可能少的内存和/或在完成时释放内存

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

public ArrayList createDataList(){
dataList=newarraylist();
BufferedReader br=null;
试一试{
br=新的BufferedReader(新的InputStreamReader(getAssets()。打开(
"text.txt),;
字符串数据;
而((data=br.readLine())!=null){
dataList.add(数据);
}                           
}捕获(IOE异常){
e、 printStackTrace();
}最后{
试一试{
br.close();//停止读取
}捕获(IOEX异常){
例如printStackTrace();
}
}
返回数据列表;
}
编辑* 异步类:

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

    }

}
私有类loadData扩展异步任务{
@凌驾
受保护的ArrayList doInBackground(无效…arg0){
dataList=createDataList();
返回数据列表;
}
受保护的void onPostExecute(ArrayList结果){
super.onPostExecute(结果);
//在TextView中将ArrayList中的第一个元素显示为测试
}
}
我尝试过根据我想要如何组织数据来分割文件,并将每个文本文件中的数据存储到一个单独的
ArrayList
中,但我也遇到了内存问题。我还将所有数据存储到一个“master”
ArrayList
,然后调用该“master”上的一个方法将数据添加到相应的
ArrayList
(在复制“master”后立即从中删除/清除数据)

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

编辑**

日志:

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


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


您可能还想在此处进行调查:

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


您可能还想在此处进行调查:

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

其次,使用
hprof
或EclipseMat之类的工具计算ArrayList占用了多少内存。如果使用了大量的空间,您可能需要考虑更紧凑的数据表示。

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


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

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

其次,使用
hprof
或EclipseMat之类的工具计算ArrayList占用了多少内存。如果使用了大量的空间,您可能需要考虑更紧凑的数据表示。

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

避免这种情况的一种方法是将文件作为
字节[]
读入内存,扫描它以找出每个字符串的起始位置,然后只保留一个带有每个字符串起始偏移量的整数数组。当需要字符串N时,将其从
字节[]
解码为
字符串
,然后返回。这大大减少了您的开销。您可以通过不加载文件,只根据需要读取单个字符串(使用
RandomAccessFile)来进一步减少它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

    }

}