【问题标题】:Android: Memory not being free'd after releasing referencesAndroid:释放引用后内存未释放
【发布时间】:2020-05-21 20:38:21
【问题描述】:

我有一个活动,我获得了大量对象,大约 25,000 个对象,总共包含大约 600,000 个字符串,这占用了大约 20MB 的堆。此列表被加载到 adapter 中,recyclerview 然后显示列表。

我的问题是,当我关闭活动并且活动被“销毁”时,庞大的对象列表不会被垃圾收集。因此,我的堆仍然包含 20MB 的对象,当我重新打开该活动时,另外 20MB 的对象被添加到堆中,并且内存很快被耗尽。

在活动的onDestroy() 方法中,我尝试释放对包含大量对象列表的adapter 的引用。我还发布了对recyclerViewviewModel 的引用,viewModel 是我从更新adapterLiveData 对象获取单词的地方。

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

虽然这不起作用,并且似乎没有从堆中删除 20MB 的对象,如下面的控制台输出所示:

(强调57MB/81MB之前显示的销毁活动并释放对象之后)

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

我已确保没有对可能使其(以及我的对象列表)保持活动状态的活动的静态引用。

对象列表在任何地方都没有被静态引用,但我确实使用不同线程中的静态方法过滤列表,如下所示:

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();

我也在过滤后释放对列表的引用,所以这应该没有问题。

【问题讨论】:

  • 这听起来像是Dump Java heap 的工作。
  • 请说明您是如何加载列表的
  • @LenaBru 我添加了更多代码来演示列表的来源。
  • getAllWordsLive()是如何获得的?
  • @LenaBru 它是一个 LiveData> 对象,它使用 SELECT * SQL 语句从我的 Room 数据库中获取列表。

标签: java android performance memory


【解决方案1】:

首先,当您发送要进行垃圾收集的东西时,它可能不一定立即被垃圾收集,或者一次全部收集。

这样,您需要检查所有包含您庞大列表的来源。 在大多数情况下,它不仅保存在适配器中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-08
    • 2011-07-18
    • 2013-07-26
    • 2011-04-02
    • 2014-06-13
    • 1970-01-01
    • 2019-05-19
    相关资源
    最近更新 更多