fluttercandies / flutter_image_compress

flutter image compress
MIT License
632 stars 215 forks source link

[Bug report] iOS memory leak #308

Closed alex-melnyk closed 3 weeks ago

alex-melnyk commented 2 months ago

Version

2.1.0

Platforms

iOS

Device Model

all iOS devices

flutter info

[✓] Flutter (Channel stable, 3.19.6, on macOS 14.5 23F79 darwin-arm64, locale en-UA)
    • Flutter version 3.19.6 on channel stable at /Users/melnyk/fvm/versions/3.19.6
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 54e66469a9 (7 weeks ago), 2024-04-17 13:08:03 -0700
    • Engine revision c4cd48e186
    • Dart version 3.3.4
    • DevTools version 2.31.1

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    • Android SDK at /Users/melnyk/Library/Android/sdk/
    • Platform android-34, build-tools 34.0.0
    • ANDROID_SDK_ROOT = /Users/melnyk/Library/Android/sdk/
    • Java binary at: /Users/melnyk/Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.10+0-17.0.10b1087.21-11572160)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.4)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 15F31d
    • CocoaPods version 1.15.0

[✓] Android Studio (version 2023.3)
    • Android Studio at /Users/melnyk/Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.10+0-17.0.10b1087.21-11572160)

[✓] Android Studio (version 2022.2)
    • Android Studio at /Users/melnyk/Applications/Android Studio Flamingo 2022.2.1 Patch 2.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b802.4-9586694)

[✓] VS Code (version 1.87.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension can be installed from:
      🔨 https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter

[✓] Connected device (4 available)
    • Melnyk iPad (mobile)          • 00008027-001D59001EE9802E • ios          • iOS 17.4.1 21E236
    • iPad mini (mobile)            • 00008110-001149412663801E • ios          • iOS 17.4.1 21E236
    • Alex Melnyk’s iPhone (mobile) • 00008130-000451220CDB803A • ios          • iOS 17.5.1 21F90
    • macOS (desktop)               • macos                     • darwin-arm64 • macOS 14.5 23F79
      darwin-arm64
    ! Error: Browsing on the local area network for Melnyk iPhone. Ensure the device is unlocked and
      attached with a cable or associated with the same local area network as this Mac.
      The device must be opted into Developer Mode to connect wirelessly. (code -27)
    ! Error: Browsing on the local area network for iPhone Барахло. Ensure the device is unlocked and
      attached with a cable or associated with the same local area network as this Mac.
      The device must be opted into Developer Mode to connect wirelessly. (code -27)
    ! Error: Browsing on the local area network for iPhone. Ensure the device is unlocked and attached
      with a cable or associated with the same local area network as this Mac.
      The device must be opted into Developer Mode to connect wirelessly. (code -27)
    ! Error: Browsing on the local area network for Melnyk iPhone. Ensure the device is unlocked and
      attached with a cable or associated with the same local area network as this Mac.
      The device must be opted into Developer Mode to connect wirelessly. (code -27)

[✓] Network resources
    • All expected network resources are available.

• No issues found!

How to reproduce?

Run an example code for 30 files at once in the loop and repeat that operation 4-5 times.

In the profile mode you can observe that memory allocated but never release.

Logs

No errors, just app crashed.

Example code (optional)

await FlutterImageCompress.compressWithFile(
        sourceFile.absolute.path,
        minWidth: 1280,
        minHeight: 720,
        quality: 85,
        autoCorrectionAngle: true,
        rotate: 0,
      );

Contact

@alex-melnyk

LarssK-TS commented 3 weeks ago

Hi @alex-melnyk when is the next release with this fix planned?

alex-melnyk commented 3 weeks ago

Hi @alex-melnyk when is the next release with this fix planned?

I'm not responsible for the release of this package. Also, I would close this issue since the root of the issue isn't there.

LarssK-TS commented 2 weeks ago

Hi @alex-melnyk what was the root cause? I've experienced battery drain on my Android test device.

alex-melnyk commented 2 weeks ago

Hi @alex-melnyk what was the root cause? I've experienced battery drain on my Android test device.

Well... to get image file resolution I've been used Image class to load the image file and get its size:

/// Returns a [Size] of the [imageFile].
static Future<Size> getImageSize(File imageFile) async {
    final completer = Completer<Size>();

    final imageStream = Image.file(imageFile).image.resolve(
          ImageConfiguration.empty,
        );

    late final ImageStreamListener listener;

    listener = ImageStreamListener(
      (image, __) {
        // Remove the listener to avoid potential memory leak
        imageStream.removeListener(listener);

        completer.complete(
          Size(
            image.image.width.toDouble(),
            image.image.height.toDouble(),
          ),
        );
      },
      onError: (exception, stackTrace) {
        // Remove the listener on error
        imageStream.removeListener(listener);

        completer.completeError(exception, stackTrace);
      },
    );

    imageStream.addListener(listener);

    return completer.future;
  }

For my case issue was related to missed lines to remove the listener, in that case platform won't release the stream and each time it propagates more and more freezes streams that allocate memory but never release it.

imageStream.removeListener(listener);