Skip to content

Unable to release FlutterViewController even when there is nothing referencing it.  #21347

Closed
@nightwolf-chen

Description

@nightwolf-chen

We‘ve embed Flutter into our existing App. The problem is that we want to release FlutterViewController when there are no Flutter Pages to save some memory. But we found that FlutterViewController can't be released even there are no references to it.

I've debug into Flutter Engine and found that there are some retain circles between FlutterChannels and FlutterViewController. I tried to break the retain circles and released FlutterViewController successfully. But there are some Skia Images leaked during the release of FlutterViewController.

I was wondering is there any official support for FlutterViewController releasing and rebuilding without those memory leak problems.

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel xy_beta_v0.5.6, v0.5.6-pre.112, on Mac OS X 10.13.5 17F77, locale zh-Hans-CN)
[✓] Android toolchain - develop for Android devices (Android SDK 27.0.3)
[✓] iOS toolchain - develop for iOS devices (Xcode 9.4.1)
[✓] Android Studio (version 3.1)
[✓] VS Code (version 1.25.1)
[✓] Connected devices (1 available)

• No issues found!

Activity

added
a: existing-appsIntegration with existing apps via the add-to-app flow
on Sep 3, 2018
xster

xster commented on Sep 18, 2018

@xster
Member
seanWongs

seanWongs commented on Oct 9, 2018

@seanWongs

Is there any progress?

jamesderlin

jamesderlin commented on Oct 9, 2018

@jamesderlin
Contributor
nightwolf-chen

nightwolf-chen commented on Oct 9, 2018

@nightwolf-chen
Author

flutter/engine#6464 This should be related to the retain circles.

dnfield

dnfield commented on Oct 9, 2018

@dnfield
Contributor

flutter/engine#6447 should make this more doable. I'm curious about the Skia images leaking though, do you have a reproduction for that by chance?

self-assigned this
on Oct 9, 2018
nightwolf-chen

nightwolf-chen commented on Oct 11, 2018

@nightwolf-chen
Author

It just happens when you dealloc shell inside FlutterViewController. When I tried to release shell, the Skia Objects unref operation causes a crash for null pointer exceptions. When I tried to avoid the crashes by skipping the unref operation the leaks happened. My guess is that the Skia images have to be released on GPU thread and there were some threads synchronization problems. It could be related to code blow.

shell deconstructor:

Shell::~Shell() {
  PersistentCache::GetCacheForProcess()->RemoveWorkerTaskRunner(
      task_runners_.GetIOTaskRunner());

  if (auto vm = blink::DartVM::ForProcessIfInitialized()) {
    vm->GetServiceProtocol().RemoveHandler(this);
  }

  fml::AutoResetWaitableEvent ui_latch, gpu_latch, platform_latch, io_latch;

  fml::TaskRunner::RunNowOrPostTask(
      task_runners_.GetUITaskRunner(),
      fml::MakeCopyable([engine = std::move(engine_), &ui_latch]() mutable {
        engine.reset();
        ui_latch.Signal();
      }));
  ui_latch.Wait();

  fml::TaskRunner::RunNowOrPostTask(
      task_runners_.GetGPUTaskRunner(),
      fml::MakeCopyable(
          [rasterizer = std::move(rasterizer_), &gpu_latch]() mutable {
            rasterizer.reset();
            gpu_latch.Signal();
          }));
  gpu_latch.Wait();

  fml::TaskRunner::RunNowOrPostTask(
      task_runners_.GetIOTaskRunner(),
      fml::MakeCopyable([io_manager = std::move(io_manager_),
                         platform_view = platform_view_.get(),
                         &io_latch]() mutable {
        io_manager.reset();
        if (platform_view) {
          platform_view->ReleaseResourceContext();
        }
        io_latch.Signal();
      }));

  io_latch.Wait();

  // The platform view must go last because it may be holding onto platform side
  // counterparts to resources owned by subsystems running on other threads. For
  // example, the NSOpenGLContext on the Mac.
  fml::TaskRunner::RunNowOrPostTask(
      task_runners_.GetPlatformTaskRunner(),
      fml::MakeCopyable([platform_view = std::move(platform_view_),
                         &platform_latch]() mutable {
        platform_view.reset();
        platform_latch.Signal();
      }));
  platform_latch.Wait();
}

unref code:

void SkiaUnrefQueue::Unref(SkRefCnt* object) {
  std::lock_guard<std::mutex> lock(mutex_);
  objects_.push_back(object);
  if (!drain_pending_) {
    drain_pending_ = true;
    task_runner_->PostDelayedTask(
        [strong = fml::Ref(this)]() { strong->Drain(); }, drain_delay_);
  }
}

void SkiaUnrefQueue::Drain() {
  std::deque<SkRefCnt*> skia_objects;
  {
    std::lock_guard<std::mutex> lock(mutex_);
    objects_.swap(skia_objects);
    drain_pending_ = false;
  }

  for (SkRefCnt* skia_object : skia_objects) {
    skia_object->unref();
  }
}
nightwolf-chen

nightwolf-chen commented on Oct 11, 2018

@nightwolf-chen
Author

Please notice this problem was on 0.5.6 beta version.

dnfield

dnfield commented on Oct 16, 2018

@dnfield
Contributor

Can you try with the code in flutter/engine#6447 and see if you're able to successfully release the view controller without memory leaks? I don't know if I'm doing exactly what you did, but I'm pretty sure it should work with that patch.

added
waiting for customer responseThe Flutter team cannot make further progress on this issue until the original reporter responds
on Oct 16, 2018
added this to the bucket10 milestone on Oct 16, 2018

9 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Relationships

None yet

    Development

    No branches or pull requests

      Participants

      @xster@zoechi@nightwolf-chen@Natoto@firetheworld

      Issue actions

        Unable to release FlutterViewController even when there is nothing referencing it. · Issue #21347 · flutter/flutter