Android: память не освобождается после публикации ссылок - PullRequest
0 голосов
/ 06 февраля 2020

У меня есть действие, которое я получаю большой список объектов, около 25 000 объектов, содержащих в общей сложности около 600 000 строк, это занимает около 20 МБ кучи. Этот список загружается в adapter для recyclerview, который затем отображает список.

Моя проблема заключается в том, что когда я закрываю действие, и действие предположительно «уничтожается», огромный список объектов не мусор собрал. Поэтому моя куча по-прежнему содержит 20 МБ объектов, и когда я снова открываю это действие, в него добавляется еще 20 МБ объектов, и память быстро израсходуется.

В методе действия onDestroy() я попытка освободить ссылку на adapter, которая содержит огромный список объектов. Я также выпускаю ссылку на recyclerView и viewModel, viewModel - это место, где я получаю слова из объекта LiveData, который обновляет adapter.

@Override
protected void onDestroy() {
    adapter = null;
    recyclerView = null;
    viewModel = null;
    Log.d("kesD", "onDestroy: pls free up my MB");
    super.onDestroy();
}

Хотя это не работает, и кажется, что 20MB объектов не удаляются из кучи, как показано в этом выводе консоли ниже:

(акцент на 57 МБ / 81 МБ , показанные до и после уничтожения действия и освобождения объектов)

2020-02-05 20:18:36.349 2042-2077/co.uk.SpeedSpanish I/uk.SpeedSpanis: Background concurrent copying GC freed 461591(31MB) AllocSpace objects, 6(312KB) LOS objects, 29% free, 57MB/81MB, paused 151us total 238.203ms
2020-02-05 20:18:36.443 2042-2042/co.uk.SpeedSpanish D/kesD: onDestroy: pls free up my MB
2020-02-05 20:18:37.198 2042-2077/co.uk.SpeedSpanish I/uk.SpeedSpanis: Background concurrent copying GC freed 445259(31MB) AllocSpace objects, 0(0B) LOS objects, 29% free, 56MB/80MB, paused 98us total 240.906ms

Я удостоверился, что нет никаких ссылок c на активность, которая может поддерживать его (и мой список объектов) живым.

Список объектов нигде не упоминается статически, но я фильтрую список с помощью метода stati c в другом потоке как показано ниже:

private void getViewModelAllWords(){
    viewModel = ViewModelProviders.of(this).get(WordViewModel.class);
    adapter = new WordDetailedAdapter(this, viewModel, this, this, false);
    viewModel.getAllWordsLive().observe(this,words -> {
        Collections.sort(words, (o1, o2) -> o1.getWord().compareToIgnoreCase(o2.getWord()));
        filterWords(words);
    });
}

private void filterWords(List<Word> words) {
    FilterThread thread = new FilterThread(words);
    thread.start();
}

private class FilterThread extends Thread{

    private List<Word> allWords;

    public FilterThread(List<Word> allWords){
        this.allWords = allWords;
    }

    @Override
    public void run() {
        if(allWords!=null){
            final List<Word> words = WordFilter.getFilteredList(allWords, wordClassStr, wordCategoryStr);
            runOnUiThread(() -> applyFilteredWords(words));
            allWords = null;
        }
    }
}

private void applyFilteredWords(List<Word> words){
    adapter.submitList(words);
}

@Query("SELECT * FROM Word ORDER BY word")
LiveData<List<Word>> getAllWordsLive();

Я также освобождаю ссылку на список после фильтрации, так что это не должно быть проблематичным c.

1 Ответ

0 голосов
/ 06 февраля 2020

Прежде всего, когда вы отправляете что-то для сбора мусора, это может не обязательно быть сборщиком мусора сразу или сразу.

При этом вам нужно проверить ВСЕ источники, которые содержат ваш огромный список. В большинстве случаев он проводится не только в адаптере.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...