Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Conversation

@dnfield
Copy link
Contributor

@dnfield dnfield commented Sep 27, 2021

Fixes flutter/flutter#90551

This PR does the following:

  • Instead of unconditionally calling Dart_NotifyLowMemory whenever we get a trim signal, use TRIM_LEVEL_RUNNING_CRITICAL and above before a first frame and TRIM_LEVEL_RUNNING_LOW after as the cutoffs.
  • Instead of calling the system channel memory pressure event only for TRIM_LEVEL_RUNNING_LOW, call it for all trim levels above RUNNING_LOW.

This can slightly raise memory usage during application initialization, but only until a first frame is rendered.

@dnfield
Copy link
Contributor Author

dnfield commented Sep 27, 2021

In local traces of customer: money's startup time, this substantially improves startup performance on a low memory 4 core device.

// not at least running critical, we should avoid delaying the frame for
// an overly aggressive GC.
boolean trim =
isFirstFrameRendered ? level >= TRIM_MEMORY_RUNNING_LOW : level > TRIM_MEMORY_RUNNING_LOW;
Copy link
Member

@xster xster Sep 27, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

>= for the last part of the ternary too so readers don't have to go look for what the next level is?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

isFirstFrameRendered ? level >= TRIM_MEMORY_RUNNING_LOW : level > TRIM_MEMORY_RUNNING_LOW;
if (trim) {
flutterEngine.getDartExecutor().notifyLowMemoryWarning();
flutterEngine.getSystemChannel().sendMemoryPressureWarning();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so we're running it more now? From being only in TRIM_MEMORY_RUNNING_LOW to all levels above TRIM_MEMORY_RUNNING_LOW?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct.

I'm not sure why the previous behavior was the way it was, but in this case we'll now run it when the app goes to background. I can move this to a separate change if you think that's worthwhile.

What's bad right now is that I suspect you can get RUNNING_CRITICAL and never hit RUNNING_LOW, or you might go to background and get one of the background related ones without ever hitting a RUNNING_* one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, to clarify:

We're running flutterEngine.getDartExecutor().notifyLowMemoryWarning() less now. This is the bigger culprit since it almost always will force an expensive GC.

We're running flutterEngine.getSystemChannel.sendMemoryPressureWarning() more now, which is less serious because it does not by itself trigger GC, just triggers a platform message to the Dart application to do cleanup.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right. I think one PR is ok. Just to check on potential expectations, is that with this PR, we might increase jank (more GC events going into the framework), and we might decrease OOM (since we're not missing some signals now). Is that right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds right to me

@dnfield
Copy link
Contributor Author

dnfield commented Sep 27, 2021

I've fixed the failing test so that it now makes sure to mark a frame as rendered for the second half.

@blasten
Copy link

blasten commented Sep 27, 2021

do we know what is causing this signal? Is this vendor specific?

@dnfield
Copy link
Contributor Author

dnfield commented Sep 27, 2021

@blasten - I see it happening on a Google specific phone at the end of Choreographer#doFrame for the first frame.

I don't know if it's vendor specific.

@blasten
Copy link

blasten commented Sep 27, 2021

...and do we know if any of this can be attributed to how different Flutter components allocate memory during this phase?

@dnfield
Copy link
Contributor Author

dnfield commented Sep 27, 2021

https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/app/ActivityThread.java;l=1629;bpv=0;bpt=1 is where this gets scheduled - you can see there that trimMemory gets pushed to the end of the next choreographer frame.

I suppose we could try to do something similar, so that we respond to onTrimMemory after the next frame is rendered by Flutter. However, this at least says if we're running critical on memory, we stop the world to do a GC the way the patch is written currently..

public void onFlutterUiDisplayed() {
host.onFlutterUiDisplayed();
isFlutterUiDisplayed = true;
isFirstFrameRendered = true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can isFlutterUiDisplayed be used instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That flips to false if the ui goes away

@dnfield
Copy link
Contributor Author

dnfield commented Sep 30, 2021

@xster the tests I've been able to run internally do not show regressions, but due to some blockers currently I haven't been able to run very many. Can we land this for now and keep an eye out as a patch that is worth looking at should regressions arise?

@dnfield dnfield merged commit a09dabb into flutter:master Sep 30, 2021
@dnfield dnfield deleted the android_on_trim branch September 30, 2021 19:46
akbiggs pushed a commit to akbiggs/engine that referenced this pull request Oct 1, 2021
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Oct 1, 2021
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Oct 1, 2021
dnfield added a commit to dnfield/engine that referenced this pull request Oct 6, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Android Embedding unconditionally calls NotifyLowMemory in onTrimMemory

4 participants