Flutter“计算”内存泄漏-如何撤消计算实例使用的堆变量? [英] Flutter 'Compute' memory leak - How do I retire heap variables used by compute instance?

查看:115
本文介绍了Flutter“计算”内存泄漏-如何撤消计算实例使用的堆变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在移动应用程序中使用也是出于这个原因。他们建议使用流控制器。


I'm trying to use a compute instance in my mobile application to reduce jank when deserializing a bunch of downloaded JSON into objects.

When I implement the deserialization method using compute, the heap keeps both the passed JSON and the returned deserialized objects (in a list) INDEFINITELY. GC is triggering normally but is not removing the objects from the heap, even when the method has closed and the parent/calling objects had been retired. As such, when using the DevTools memory profiler, it shows runaway memory consumption - the heap just keeps getting bigger.

Normal Memory Profile - memory usage hovers around 45MB when the deserialization method is called directly (but it causes jank in the app)

Runaway Memory Profile - memory usage increases linearly and is never retired when the deserialization method is called via compute (but it doesn't cause jank in the app)

static Stream<EventCommitInfoModel> getEventsAfterDate(DateTime date) async* {

    // variable defs for scope reuse

    while (count < maxCount && retryCount > 0) {
      try {
        json = await http.read(url);

        // currentEvents = await compute(EventModel.fromJsonArray, json);
        currentEvents = EventModel.fromJsonArray(json);

        db = await AppStateModel.database;
        await db.upsertEventModels(currentEvents);
        yield new InfoModel(maxCount, currentEvents.length);
      }
      catch (ex) {

        // try again or close

      }
    }

    print("stream is closing.");
  }

In the code above, the relevant lines begin with "currentEvents = ". The normal memory behavior is seen with:

  currentEvents = EventModel.fromJsonArray(json);

and the runaway memory behavior is seen with:

  currentEvents = await compute(EventModel.fromJsonArray, json);

PLEASE NOTE THAT CHANGING EventModel.fromJsonArray to an async method has NO impact on any of the profiling above. Nor does changing it to async cause the jank to go away. I have already considered that. I can add artificial delays into the code in order to introduce async splits in the mapping method, but that's NOT what I want to do here - I need the data to return as fast as possible, which is why using compute is ideal.

Even after "stream is closing" is printed, and the stream is closed, and the parent object is retired from the hierarchy and collected, any memory associated with the compute method is never retired.

How do I get the compute instance to retire memory properly? Is there something I'm doing wrong here?

解决方案

Without more code, what seems to be happening is that the stream you are creating is never having actually closing. So the stream remains open, and thus has hooks into the json objects which GC cannot then remove.

You imply in your problem statement that the stream is getting closed:

Even after "stream is closing" is printed, and the stream is closed, and ...

... But a print statement that the stream is closing doesn't close the stream. Just getting to the end of the code block does not close the stream either (especially for a broadcast stream), at least afaik.

Also per the dart documentation they don't recommend operating on streams directly; https://dart.dev/articles/libraries/creating-streams#final-hints for exactly this reason too. They recommend using a stream controller.

这篇关于Flutter“计算”内存泄漏-如何撤消计算实例使用的堆变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆