Android: чтение файлов - проблема OutOfMemory

1

Я создаю приложение, которое включает чтение данных из файла. Файл относительно большой (1,8 МБ) и считывается из асинхронного потока в onCreate. В первый раз, когда приложение запущено, оно загружается просто отлично. Однако, если вы нажмете кнопку "Назад", а затем загрузите ее снова, у нее закончится нехватка памяти и сбои (выброс ошибки OutOfMemory).

Как мне заставить его использовать наименьший объем памяти и/или освобождать эту память, когда это будет сделано?

Код чтения файлов (выполнен в методе doInBackground() класса async):

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;
}

ИЗМЕНИТЬ * Класс Async:

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 (удаление/очистка данных от "мастера", как только он копируется).

Любые идеи о том, как оптимизировать и уменьшить влияние памяти?

ИЗМЕНИТЬ **

Logcat:

Изображение 174551

То есть, когда вы нажимаете кнопку "Назад", а затем снова загружаете действие. Ниже приведено только одно из сообщений (в подробностях):

Изображение 174551

Теги:
android-assets
android-memory

3 ответа

0
Лучший ответ

Во-первых, убедитесь, что у вас нет двух копий данных в памяти. Вы можете исключить ссылку на старый ArrayList, прежде чем приступать к созданию нового, хотя вы должны сделать это осторожно: сначала вызов ArrayList.clear() будет более тщательным.

Во-вторых, выясните, сколько памяти ArrayList съедает с помощью инструмента, такого как hprof или Eclipse MAT. Если он использует тонну пространства, вы можете рассмотреть более компактное представление данных.

Итак... из фрагмента кода, похоже, вы просто читаете кучу текстовых строк из файла, используя преобразование byte-to- char. Если исходный материал является простым UTF-8 (то есть, по существу, ASCII), у вас есть расширение 2x для UTF-16, а также выделение объекта char [] для его хранения, а также размер объекта String, который обертывает что плюс накладные расходы на запись в ArrayList. В зависимости от того, как долго средняя строка в файле, это может быть значительным числом на вашем 1.8MB.

Один из способов избежать этого - прочитать файл в памяти как byte[], отсканировать его, чтобы выяснить, где начинается каждая строка, и просто сохранить массив целых чисел со стартовым смещением каждой строки. Когда вам понадобится строка N, декодируйте ее с byte[] в String и верните ее. Это значительно снижает ваши накладные расходы. Вы можете уменьшить его, не загружая файл и просто считывая отдельные строки при необходимости (используя RandomAccessFile), но это может замедлить работу.

  • 0
    Я очищаю ArrayList, когда это делается, копируя данные в нужные ArrayList. Текстовый файл находится в формате UTF-8, а строки не длиннее 15. Я не уверен, как будет работать массив байтов (я никогда раньше не читал файл таким образом). Не могли бы вы немного рассказать о том, как это работает, и, возможно, (если бы вы могли) представить эквивалент того, что у меня есть? Я подумаю о том, как я могу заставить работать RandomAccessFile (если смогу для своих целей) в зависимости от того, как это работает. Я должен буду читать об этом также, поскольку я не работал с этим также. :)
  • 0
    RandomAccessFile на самом деле выглядит довольно прилично. Я, честно говоря, никогда не слышал об этом до того, как вы упомянули об этом. Мне просто нужно было бы иметь возможность проверять / перебирать строки в файле, пока он не найдет те, которые удовлетворяют условиям; похоже, это возможно.
Показать ещё 5 комментариев
0

Кажется, у вас могут быть проблемы с неизменностью строк.

Почему бы вам не попробовать изменить код, чтобы использовать StringBuilder? Конечно, вам придется изменить несколько вещей, но это будет достаточно похоже на ваш код и не будет заполнять вашу память так же быстро.

  • 0
    Сколько места будет сэкономлено? Я всегда стараюсь сделать все как можно более легким и легким в использовании ресурсов (например, мои фоны всегда имеют темные цвета для экономии заряда батареи). Устранит ли это проблему, если пользователь нажмет кнопку «Назад», а затем перезапустит ее?
  • 0
    Проблема в том, что любая новая строка, которую вы создаете, висит в куче, пока ... ну, пока все ссылки не будут уничтожены. В документации говорится: «Несколько строк могут совместно использовать один и тот же char [], потому что строки неизменны. Метод substring (int) всегда возвращает строку, которая разделяет базовый массив его исходной строки. Как правило, это оптимизация: требуется меньше символьных массивов. распределяться, и копирование необходимо меньше. Но это также может привести к нежелательному удержанию кучи ». Итак, по определению вы тратите пространство памяти, используя строки.
Показать ещё 2 комментария
0

Вы можете попробовать добавить android:largeHeap="true" в манифест, но он не поддерживается в Android API-8. Насколько я понимаю, вы читаете и храните данные в кучевую память, которая обычно довольно ограничена, и ее размер зависит от устройства, на котором работает ваше приложение.

Вы также можете изучить здесь: android - из памяти

  • 0
    Я не полностью понимаю весь код в этой ссылке, но из того, что я получил из принятого ответа, данные записываются в файл. Это кажется контрпродуктивным, если вы читаете из файла, а затем записываете в другой файл. Или я не прав? Чтобы получить данные из файла, в который вы записали, вам придется прочитать его снова. Похоже, вы выполняете работу более чем вдвое. Опять же, у меня никогда раньше не было проблем с памятью, потому что это первое приложение, которое я делаю, которое включает чтение данных из файла.
  • 0
    Я мог бы иметь длинный метод с тысячами dataList.add(); заявления, чтобы избежать чтения из файла. Однако это не кажется очень практичным, и я не хочу этого делать, если я могу избежать этого.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню