Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Animated gif is causing my App to crash on some Android devices and iOS 12. Seems fine on iOS 11 and below. #20998

Closed
mjaffa-figure opened this issue Aug 24, 2018 · 35 comments · Fixed by #22452
Assignees
Labels
c: crash Stack traces logged to the console e: device-specific Only manifests on certain devices engine flutter/engine repository. See also e: labels. platform-ios iOS applications specifically waiting for PR to land (fixed) A fix is in flight

Comments

@mjaffa-figure
Copy link

mjaffa-figure commented Aug 24, 2018

Steps to Reproduce

  1. Initialize a Widget with this
new Container(constraints: BoxConstraints.tightFor(
                              width: width, height: width),
                              child: new Image(
                                  image: new AssetImage("assets/myanimatedgif.gif")))

The animated gif is about 10 MB

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel dev, v0.7.0, on Mac OS X 10.13.6 17G2208, locale en-US)
[✓] Android toolchain - develop for Android devices (Android SDK 28.0.1)
[✓] iOS toolchain - develop for iOS devices (Xcode 9.4.1)
[✓] Android Studio (version 3.1)
[!] VS Code (version 1.26.0)
[✓] Connected devices (1 available)

! Doctor found issues in 1 category.
@zoechi
Copy link
Contributor

zoechi commented Aug 24, 2018

Can you provide any error output? Perhaps using flutter logs?
Can you make the gif file available?

@mjaffa-figure
Copy link
Author

mjaffa-figure commented Aug 24, 2018

When I do flutter run this is what I get right before it crashes. The animated gif is on my first screen:

git/my-app-name/.packages --filesystem-scheme org-dartlang-root
[ +156 ms] flutter: Checking deeplinks
[ +287 ms] flutter: Deeplink return
[   +6 ms] flutter: Settings registered: PushNotificationSettings {sound: true, alert: true, badge: true}
[   +1 ms] flutter: fglHK1K4OWg:APA91bGaz79tTJOzY3WK5k_5QXJSS6OCHwcX7MJiWyQbhLpno1CRE74INwz1izCOkki8zw6WoFwTyHk-rdcYPfRT4_GOurud-mAXxSDOdzdiZx_btfGgtEv_FBcZodwTnOLXVUoFMM4l
[+3531 ms] Updating files
[+2712 ms] DevFS: Sync finished
[        ] Syncing files to device iPhone... (completed)
[        ] Synced 50.1MB.
[   +1 ms] _flutter.listViews: {isolateId: isolates/891318167}
[   +2 ms] Connected to _flutterView/0x104120b28.
[        ] 🔥  To hot reload changes while running, press "r". To hot restart (and rebuild state), press "R".
[        ] An Observatory debugger and profiler on iPhone is available at: http://127.0.0.1:1024/
[        ] For a more detailed help message, press "h". To quit, press "q".
[+16104 ms] Service protocol connection closed.
[   +1 ms] Lost connection to device.
[   +2 ms] DevFS: Deleting filesystem on the device (file:///private/var/mobile/Containers/Data/Application/1A6D4552-9370-40D6-B982-716F011E27E1/tmp/my-app-nameGvCbmS/my-app-name/)
[        ] _deleteDevFS: {fsName: my-app-name}
[ +256 ms] TimeoutException after 0:00:00.250000: Future not completed
[   +5 ms] "flutter run" took 98,256ms.

@mjaffa-figure
Copy link
Author

same thing with flutter logs

@mjaffa-figure
Copy link
Author

When I comment out the Image with the animated gif. Does not crash.

@zoechi
Copy link
Contributor

zoechi commented Aug 25, 2018

Can you make the image available or can you try if you can reproduce with an available image?

@zoechi zoechi added c: crash Stack traces logged to the console engine flutter/engine repository. See also e: labels. labels Sep 2, 2018
@mjaffa-figure
Copy link
Author

how can I get the file to you, it is 24 MB

@mjaffa-figure
Copy link
Author

It is crashing on iOS 11 as well. I ran the Flutter app on my Wife's phone last night.

@zoechi
Copy link
Contributor

zoechi commented Sep 4, 2018

24MB shouldn't be an issue. Can you upload here or do you rather not have it public?

@mjaffa-figure
Copy link
Author

I would rather not have it public, eventually when my app is released I will release it public for fun. But I tried uploading here and it says 24 mb is too big.

@zoechi
Copy link
Contributor

zoechi commented Sep 4, 2018

I see. If I have the image I can try to reproduce it here, but that won't buy us much, you already reproduce on different devices.

The people working on fixing the bug are at the other side of the planet ;-)
It's probably best we just wait for one of them to request it from you.

@mjaffa-figure
Copy link
Author

ok, thanks

@mjaffa-figure
Copy link
Author

When do you think they will be interested into looking into this? We are planning on releasing in less than a month and will have to just rip out the animated gifs if we can't get this looked at.

@zoechi
Copy link
Contributor

zoechi commented Sep 5, 2018

I don't know about that. There is a lot in the pipeline.
@cbracken perhaps?

@cbracken
Copy link
Member

cbracken commented Sep 5, 2018

Hi @mjaffa-figure, would you mind pulling the crash reports and pasting them here?

Open Xcode with the device attached on which you had the crash, then go to Window > Devices and Simulators, select your device and pick the crash report, which should include the stack trace and other info.

@cbracken
Copy link
Member

cbracken commented Sep 5, 2018

/cc @amirh

@mjaffa-figure
Copy link
Author

mjaffa-figure commented Sep 5, 2018

This is the iOS 12 log on an iPhone X. Let me know if you need an iOS 11 with iPhone 8, I can capture that as well.

@cbracken @amirh

Let me know if you need the animated gif sent to you. It is 24 MB like I mention above so we would need to find another way to send to you.

flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel dev, v0.7.5, on Mac OS X 10.13.6 17G2208, locale en-US)
[✓] Android toolchain - develop for Android devices (Android SDK 28.0.1)
[✓] iOS toolchain - develop for iOS devices (Xcode 10.0)
[✓] Android Studio (version 3.1)
[!] VS Code (version 1.26.1)
[✓] Connected devices (4 available)

! Doctor found issues in 1 category.

Here is the crash log.

Runner 9-5-18, 7-09 AM.log

@amirh
Copy link
Contributor

amirh commented Sep 5, 2018

It will be great if you could share the file, maybe through Google Drive?

@mjaffa-figure
Copy link
Author

mjaffa-figure commented Sep 5, 2018

@amirh

Ok will do:

new Container(constraints: BoxConstraints.tightFor(
width: width, height: width),
child: new Image(
image: new AssetImage("assets/poo.gif")))

Here is the google Drive link:
https://drive.google.com/file/d/1zFoH6F1_cc5rddi7pj6EHZgjXTom0bC9/view?usp=sharing

@mklim mklim self-assigned this Sep 10, 2018
@mklim
Copy link
Contributor

mklim commented Sep 11, 2018

I haven't reproduced a crash on initial load, but I am consistently seeing Jetsam terminating the app after 5 or seconds of the gif running. Test patch here, on hello_world. Asset isn't included in the commit.

In the crash report included earlier in the issue it looks like the process was terminated by iOS itself (SIGKILL) because it was blocking the main thread for too long (Termination Reason: Namespace ASSERTIOND, Code 0x8badf00d). More info here. The report lists what was happening in the main thread at the time, but nothing in there is jumping out at me. Going to keep digging into this more.

@zoechi zoechi added e: device-specific Only manifests on certain devices platform-ios iOS applications specifically labels Sep 11, 2018
@mjaffa-figure
Copy link
Author

mjaffa-figure commented Sep 11, 2018

@zoechi @mklim @amirh

Still getting crash in:

Running flutter doctor...
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel master, v0.8.3-pre.24, on Mac OS X 10.13.6 17G2208, locale en-US)
[✓] Android toolchain - develop for Android devices (Android SDK 28.0.1)
[✓] iOS toolchain - develop for iOS devices (Xcode 10.0)
[✓] Android Studio (version 3.1)
[!] VS Code (version 1.27.1)
[✓] Connected devices (1 available)

@mjaffa-figure
Copy link
Author

Oh sorry, I was asked by @zoechi to test another issue on this build, not this issue, but yeah this one still no working. 😢

@mjaffa-figure
Copy link
Author

@mklim @amirh I checked out #6230, looks like it is pretty close. Let me know when this gets into the master branch and I can update my flutter to try this fix out.

@mklim
Copy link
Contributor

mklim commented Sep 26, 2018

Will keep you posted @mjaffa-figure. You may want to keep an eye out for flutter/engine#6310. That should fix this problem in most cases. It's likely to go in first even though it's newer. flutter/engine#6230 is a broader fix but its behavior is surprising and conditional, so it's not going to be merged in as the primary way of handling this.

@mklim mklim added this to the bucket9 milestone Sep 26, 2018
@mklim mklim added the waiting for PR to land (fixed) A fix is in flight label Oct 8, 2018
@goderbauer goderbauer modified the milestones: bucket9, Overdue Oct 9, 2018
mklim pushed a commit that referenced this issue Oct 15, 2018
Users can set `PaintingBinding.decodedCacheRatioCap` to control the max
amount of memory used per image to avoid decoding frames each animation
loop.

This depends on flutter/engine#6310.

Fixes #20998, and fixes #14344
@tsun424
Copy link

tsun424 commented Nov 21, 2018

@mklim , I just upgraded to the latest beta of flutter, but crash still happens on iPad, do I need to change anything from my code? Thanks.
Following is my flutter version:

$ flutter --version
Flutter 0.11.8 • channel beta • https://github.com/flutter/flutter.git
Framework • revision f5b02e3c05 (10 hours ago) • 2018-11-20 07:49:29 -0800
Engine • revision 1baf081343
Tools • Dart 2.1.0 (build 2.1.0-dev.9.4 f9ebf21297)

@mklim
Copy link
Contributor

mklim commented Nov 21, 2018

@tsun424 thanks for the report. Ideally this should be fixed without anything else required. But one problem I can think of is that the fix doesn't address problems caused by loading multiple gifs at once. You should be able to disable all caching and fix crashers from this in your app by setting the decoded cache ratio to 1.0. That will completely stop frame caching so should preserve your memory across the board, at the cost of more CPU usage to decode frames each time the image loops. Can you try that and let me know if it fixes your issue? Also, are you seeing this with just one image or multiple? And on what model/OS version of iPad specifically? Thanks!

@tsun424
Copy link

tsun424 commented Nov 21, 2018

Hi @mklim , thanks for your response. I just did another test, tried to set decodedCacheRatioCap to 1.0, my testing is quite simple, just load one gif file into Image, the app still crashes after around 40 seconds playing, following is code snippet, can you please confirm if my setting is correct in initState()?

class _ThirdSlideState extends State<ThirdSlide> {
  @override
  void initState() {
    PaintingBinding.instance.decodedCacheRatioCap = 1.0;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(color: Theme.of(context).primaryColor),
      child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
        Expanded(
          child: Image(
            image: AssetImage("assets/welcome1.gif"),
            fit: BoxFit.cover,
          ),
        ),
      ]),
    );
  }
}

From my testing, this crash only happens when it's a large gif file, small gif works fine, and the large gif can be playing, just crash suddenly.

iPad Specs: I tested this from iPad(iOS 10.3.3) and iPad mini(iOS 10.3.3)

@mklim
Copy link
Contributor

mklim commented Nov 27, 2018

Hey @tsun424, thanks for the extra info and for your patience. That code does look right to me. If decodedCacheRatioCap is set after the image is loaded it wouldn't retroactively do anything, but as far as I can tell setting it in initState() should always cap the cache before the image is loaded. So far that sample code looks like it's dropping the cached frames correctly for me, unfortunately. I haven't been able to reproduce any memory issues on my end. Could you upload a large gif you've seen the crash happen with? I'd like to check and see if it's possible that there's something unexpected happening based on the files themselves specifically.

@tsun424
Copy link

tsun424 commented Nov 28, 2018

Hi @mklim , I've created a simple app(using code snippet in my last comment) for testing and done several tests on different iPads/Android devices, following is what I've observed, my testing gif file is 16MB, which is over the max image limitation(10MB) of github, couldn't upload here, I can upload somewhere else if you want to use it to test, but from my testing, I guess this issue is related with iOS versions, see below testing result:

  1. iPad 10.3.3, crashed after about 53 seconds playing
  2. iPad Mini 10.3.3, crashed after about 53 seconds playing
  3. iPad 11.0.3, keep playing several times, no crash observed
  4. Android 7.0, keep playing several time, no crash observed

Result: crash only happened on specific iOS version, it's iOS 10.3.3 from my testing, and crash happened at the same time(after 53 seconds playing).

I am sure you can reproduce it if you have such version(iOS 10.3.3) of iOS device. Please let me know if you need any further information. Thanks.

@mklim
Copy link
Contributor

mklim commented Nov 28, 2018

@tsun424 thanks again for the extra info. I still haven't been able to reproduce this unfortunately. It's just an educated guess, but I think the problem you're seeing may be that the image you're using has a bunch of "required" frames. We still always cache those, so that's one way I can think of where you would still be seeing this with a single image. I'd like to see your file to confirm for sure that that's the issue you're seeing though. Could you possibly upload the GIF to another file hosting service besides Github and link it here?

Here's the full main.dart I'm using to test. test.gif is a 26mb file with a over a hundred frames.

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class ThirdSlide extends StatefulWidget {
  @override
  _ThirdSlideState createState() => _ThirdSlideState();
}

class _ThirdSlideState extends State<ThirdSlide> {
  @override
  void initState() {
    PaintingBinding.instance.decodedCacheRatioCap = 1;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(color: Theme.of(context).primaryColor),
      child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
        Expanded(
          child: Image(
            image: AssetImage("assets/test.gif"),
            fit: BoxFit.cover,
          ),
        ),
      ]),
    );
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) => Container(child: ThirdSlide());
}

I've experimented with a few different cache settings, here's the behavior I'm seeing on 10.3.3:

  • using the default limit: App allocates about 145MB and then memory usage flattens, runs indefinitely.
  • 1.0: App allocates 52MB and then memory usage flattens, runs indefinitely.
  • 999999999 (effectively no cache limit): App linearly climbs up to 550MB before being shut down by the OS, takes about 15 seconds.

One thing worth noting is that I haven't been able to get a 10.3.3 iPad specifically to test with so far, my 10.3.3 device is an iPhone. There could also be something about 10.3.3 iPads that causes this to happen, but I'm thinking the required frames issue is more likely.

@tsun424
Copy link

tsun424 commented Nov 28, 2018

Hi, @mklim , I've uploaded the gif file to google drive, you can download it from below link and see if you can reproduce the issue.
https://drive.google.com/open?id=1RylXGZ4WrXUehX9GTI7mY6Ai-shb8bE6

For gif files, I've tested 3 different gif files(they are all converted from mp4 files to gif by a same tool, maybe that's the issue) on those devices, they all had similar crash issue.
BTW, my testing code is pretty much same with your above one.

@mklim
Copy link
Contributor

mklim commented Nov 29, 2018

Thanks @tsun424! That's enough for me to debug the issue. I filed #24835 to track this.

From what I can tell every single frame in test.gif is marked as "required", so the cache limit effectively isn't being applied to the file at all. I saw the app try to cache 231 frames before it crashed. An immediate workaround you could try in the meantime would be to try to convert the MP4s to GIFs in a different way to avoid marking all those frames as required. Typically a frame is marked as required when there's a frame that follows it that reuses some amount of pixels from the original frame. This chart from an article on GIF decoding in Chromium illustrates the idea, with frame0 being a required frame and frame1 and frame2 being dependent frames:

chart

With any luck there may be a setting in the tool you're using to encode with more independent frames, or you may be able to find and use a different tool that encodes the files differently. I'll work on updating codec.cc to fix the linked issue so it doesn't need to cache all the required frames to decode the dependent ones.

@tsun424
Copy link

tsun424 commented Nov 29, 2018

Hi @mklim , cheers! 🍺 Thanks for your analysis and suggestion, I'll try the workaround solution and keep an eye on the new issue you created.

@cbracken
Copy link
Member

cbracken commented Nov 29, 2018

I wonder if there are simple ways in which our tooling/the framework could be doing a better job of surfacing these sorts of issues to users? If not, maybe mention these sorts of issues in the docs for image widgets? @mklim @amirh thoughts?

@mklim
Copy link
Contributor

mklim commented Nov 29, 2018

@cbracken #6500 is open for providing better stack traces when we run out of memory. As far as I can tell it's blocked on #22818, adding handling for engine crashes in general. I think that's probably the most robust way of making crashes like this less opaque, but adding it in is going to be complex.

It may be worth adding a page to the Wiki on potential memory issues around images, or memory issues in general? We could also mention in the framework headers that animated images are expensive to render so to be careful with adding large files. Neither of those would really be obvious in the case of a crash though.

@github-actions
Copy link

github-actions bot commented Aug 8, 2021

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 8, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
c: crash Stack traces logged to the console e: device-specific Only manifests on certain devices engine flutter/engine repository. See also e: labels. platform-ios iOS applications specifically waiting for PR to land (fixed) A fix is in flight
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants