Skip to content

[vector_graphics] Fix memory leaks and activate leak testing [prod-leak-fix] - #8373

Merged
auto-submit[bot] merged 6 commits into
flutter:mainfrom
ValentinVignal:vector-graphics/activate-leak-testing
Jan 28, 2025
Merged

[vector_graphics] Fix memory leaks and activate leak testing [prod-leak-fix]#8373
auto-submit[bot] merged 6 commits into
flutter:mainfrom
ValentinVignal:vector-graphics/activate-leak-testing

Conversation

@ValentinVignal

Copy link
Copy Markdown
Contributor

The package manipulates disposable objects. This PR

  • Fixes some memory leaks.
  • Activates leak testing to make sure disposable objects are correctly disposed.

See the documentation: https://github.com/dart-lang/leak_tracker/blob/main/doc%2Fleak_tracking%2FDETECT.md

Pre-launch Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@ValentinVignal

Copy link
Copy Markdown
ContributorAuthor

cc @polina-c

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't really understand what this is doing?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

For the test Can render VG with image from test/vector_graphics_test.dart, leak_tracker_flutter_testing was not happy because the ImageInfo was not disposed from this callback was never disposed.

So here I am disposing it. However, disposing it also disposes it image.image, that's why I'm cloning it first.

 Expected: leak free
Actual: <Instance of 'Leaks'>
Which: contains leaks:
# The text is generated by leak_tracker.
# For leak troubleshooting tips open:
# https://github.com/dart-lang/leak_tracker/blob/main/doc/leak_tracking/TROUBLESHOOT.md
notDisposed:
total: 1
objects:
ImageInfo:
test: Can render VG with image
identityHashCode: 137082098
context:
start: >
#6_______dispatchFlutterEventToLeakTracker_(package:leak_tracker_flutter_testing/src/testing.dart:74:23)
#7______FlutterMemoryAllocations.dispatchObjectEvent_(package:flutter/src/foundation/memory_allocations.dart:249:23)
#8______FlutterMemoryAllocations.dispatchObjectCreated_(package:flutter/src/foundation/memory_allocations.dart:283:5)
#9______new_ImageInfo_(package:flutter/src/painting/image_stream.dart:51:34)
#10_____ImageInfo.clone_(package:flutter/src/painting/image_stream.dart:72:12)
#11_____ImageStreamCompleter.setImage_(package:flutter/src/painting/image_stream.dart:755:32)
#12_____StackZoneSpecification._registerUnaryCallback.<anonymous_closure>.<anonymous_closure>_(package:stack_trace/src/stack_zone_specification.dart:127:36)
#13_____StackZoneSpecification._run_(package:stack_trace/src/stack_zone_specification.dart:207:15)
#14_____StackZoneSpecification._registerUnaryCallback.<anonymous_closure>_(package:stack_trace/src/stack_zone_specification.dart:127:24)
#15______rootRunUnary_(dart:async/zone.dart:1422:47)
#16______CustomZone.runUnary_(dart:async/zone.dart:1324:19)
#17_____Future._propagateToListeners.handleValueCallback_(dart:async/future_impl.dart:902:45)
#18_____Future._propagateToListeners_(dart:async/future_impl.dart:931:13)
#19_____Future._completeWithValue_(dart:async/future_impl.dart:707:5)
<asynchronous_suspension>
package:matcher expect
package:leak_tracker_testing/src/leak_testing.dart 69:24 LeakTesting.collectedLeaksReporter.<fn>
package:leak_tracker_flutter_testing/src/testing.dart 70:37 maybeTearDownLeakTrackingForAll
===== asynchronous gap ===========================
dart:async _CustomZone.registerBinaryCallback
package:flutter_test/src/test_compat.dart 287:3 _tearDownForTestFile

Is there a better way you have in mind?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

What are your thoughts on this @jonahwilliams ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Making changes to the library to work around leak tracker is not reasonable.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

The way I understood it was that the leak tracker detected a memory leak in the library (ImageInfo is never being disposed) and what I did here was an attempt to fix this memory leak.

Are you saying this is

  1. Not a memory leak but a false positive? In that cases where is the ImageInfo usually disposed in production and would you know what is missing to the test to get it disposed too?
  2. This is a memory leak but my fix is not the proper way to do it? In that case, would you have suggestions of what I could do instead?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't know if this is a memory leak or a false positive (likely the latter), but even if this was memory leak I don't understand how to proposed change fixes it. it seems like what you're actually doing is working around leak tracker.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

For context, this is the failing test:

testWidgets('Can render VG with image', (WidgetTester tester) async {
constString bluePngPixel =
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPj/HwADBwIAMCbHYQAAAABJRU5ErkJggg==';
finalVectorGraphicsBuffer buffer =VectorGraphicsBuffer();
constVectorGraphicsCodec codec =VectorGraphicsCodec();
codec.writeSize(buffer, 100, 100);
codec.writeDrawImage(
buffer,
codec.writeImage(buffer, 0, base64Decode(bluePngPixel)),
0,
0,
100,
100,
null,
);
finalUniqueKey key =UniqueKey();
finalTestBytesLoader loader =TestBytesLoader(buffer.done());
// See listener.dart.
finalint imageKey =Object.hash(loader.hashCode, 0, 0);
expect(imageCache.currentSize, 0);
expect(imageCache.statusForKey(imageKey).untracked, true);
await tester.pumpWidget(RepaintBoundary(
key: key,
child:VectorGraphic(
loader: loader,
width:100,
height:100,
),
));
expect(imageCache.currentSize, 0);
expect(imageCache.statusForKey(imageKey).pending, true);
// A blank image, because the image hasn't loaded yet.
awaitexpectLater(
find.byKey(key),
matchesGoldenFile('vg_with_image_blank.png'),
);
expect(imageCache.currentSize, 1);
expect(imageCache.statusForKey(imageKey).live, false);
expect(imageCache.statusForKey(imageKey).keepAlive, true);
await tester.runAsync(() => vg.waitForPendingDecodes());
await tester.pump();
expect(imageCache.currentSize, 1);
expect(imageCache.statusForKey(imageKey).live, false);
expect(imageCache.statusForKey(imageKey).keepAlive, true);
// A blue square, becuase the image is available now.
awaitexpectLater(
find.byKey(key),
matchesGoldenFile('vg_with_image_blue.png'),
);
}, skip: kIsWeb);

At the end of this test, an ImageInfo remains undisposed. At first glance, I don't see anything wrong with the test itself, so this appears to be a memory leak.

Currently, FlutterVectorGraphicsListener only stores image.image and disposes of it in its toPicture method, leaving the outer ImageInfo unmanaged. I attempted to address this by disposing of the ImageInfo immediately.

Would it make sense to store the ImageInfo instead of just the Image to ensure everything gets properly disposed of in FlutterVectorGraphicsListener.toPicture?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I pushed the change in Store and dispose ImageInfo

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

That makes more sense

@polina-cpolina-c changed the title [vector_graphics] Fix memory leaks and activate leak testing[vector_graphics] Fix memory leaks and activate leak testing [prod-leak-fix]Jan 7, 2025
@polina-cpolina-c added the a: leak tracking Issues and PRs related to memory leaks detected by leak_tracker label Jan 7, 2025
@ValentinVignal
ValentinVignalforce-pushed the vector-graphics/activate-leak-testing branch from a456583 to 49637d0CompareJanuary 15, 2025 13:47
@ValentinVignal
ValentinVignalforce-pushed the vector-graphics/activate-leak-testing branch from 49637d0 to 08792f3CompareJanuary 18, 2025 05:23
@@ -1,3 +1,7 @@
## 1.1.16

* Fixes some memory leaks.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please add a more descriptive changelog entry.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sure, what do you think of More description changelog?

@jonahwilliamsjonahwilliams left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

@jonahwilliamsjonahwilliams added the autosubmit Merge PR when tree becomes green via auto submit App label Jan 28, 2025
@auto-submit
auto-submitBot merged commit 4e01110 into flutter:mainJan 28, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jan 29, 2025
jonahwilliams pushed a commit that referenced this pull request Jan 31, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Feb 5, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Feb 5, 2025
github-merge-queueBot pushed a commit to flutter/flutter that referenced this pull request Feb 5, 2025
flutter/packages@02c6fef...e6ce02c
2025-02-05 65381000+raju8000@users.noreply.github.com [vector_graphics]
Allow transition between placeholder and loaded image to have an
animation (flutter/packages#8195)
2025-02-04 andrechalella@gmail.com [flutter_markdown] Make custom table
column alignments work when text wraps (flutter/packages#8340)
2025-02-04 10687576+bparrishMines@users.noreply.github.com
[interactive_media_ads] Adds internal wrapper for iOS native
`IMAAdPodInfo` (flutter/packages#8429)
2025-02-03 tarrinneal@gmail.com [pigeon] reorg generator files
(flutter/packages#8532)
2025-02-03 byoungchan.lee@gmx.com [pigeon] [swift] Fix `PigeonError`
sendability conformance in Swift 6 (flutter/packages#8302)
2025-02-03 engine-flutter-autoroll@skia.org Roll Flutter from
b007899 to 8e2a6fc (61 revisions) (flutter/packages#8556)
2025-02-03 20989940+aednlaxer@users.noreply.github.com
[google_maps_flutter] Support for Ground Overlay - platform interface
(flutter/packages#8518)
2025-01-31 737941+loic-sharma@users.noreply.github.com [tool] Add
--xcode-warnings-exceptions flag (flutter/packages#8524)
2025-01-31 stuartmorgan@google.com [tool] Ensure that injected
dependency overrides are sorted (flutter/packages#8542)
2025-01-31 jonahwilliams@google.com [vector_graphics] Revert leak
tracker change (flutter/packages#8544)
2025-01-31 parlough@gmail.com [shared_preferences_tool] Loosen
vm_service constraint to allow for 15 (flutter/packages#8539)
2025-01-31 32538273+ValentinVignal@users.noreply.github.com
[in_app_purchase] Activate leak testing for android
(flutter/packages#8369)
2025-01-31 cunderw@gmail.com [flutter_markdown] Allow tables to be
scrollable with IntrinsicColumnWidth (flutter/packages#8526)
2025-01-30 goderbauer@google.com Update CODEOWNERS for pkg:animations
(flutter/packages#8534)
2025-01-30 engine-flutter-autoroll@skia.org Roll Flutter from
c1ffaa9 to b007899 (43 revisions) (flutter/packages#8527)
2025-01-30 pawel.jakubowski@leancode.pl [video_player_web] Adjust Web
implementation to the new platform interface (flutter/packages#8528)
2025-01-30 tarrinneal@gmail.com [shared_preferences] Exposed
SharedPreferencesOptions. (flutter/packages#8530)
2025-01-29 stuartmorgan@google.com Re-land [shared_preferences] Add
shared preferences devtool (flutter/packages#8531)
2025-01-29 84978733+alejandro-all-win-software@users.noreply.github.com
[in_app_purchase_storekit] Add Swift Package Manager compatibility
(flutter/packages#8469)
2025-01-29 stuartmorgan@google.com Revert "Re-land [shared_preferences]
Add shared preferences devtool" (flutter/packages#8529)
2025-01-29 32538273+ValentinVignal@users.noreply.github.com
[go_router_builder] Fixes trailing `?` by comparing iterables
(flutter/packages#8521)
2025-01-29 737941+loic-sharma@users.noreply.github.com [tool] Refactor
args of strings or YAML file lists (flutter/packages#8513)
2025-01-28 48155875+Michae1Weiss@users.noreply.github.com [go_router]
Add missing await keyword to onTap callback in the code example in
`navigation.md` (flutter/packages#8343)
2025-01-28 stuartmorgan@google.com Re-land [shared_preferences] Add
shared preferences devtool (flutter/packages#8519)
2025-01-28 32538273+ValentinVignal@users.noreply.github.com
[vector_graphics] Fix memory leaks and activate leak testing
[prod-leak-fix] (flutter/packages#8373)
If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages-flutter-autoroll
Please CC flutter-ecosystem@google.com on the revert to ensure that a
human
is aware of the problem.
To file a bug in Flutter:
https://github.com/flutter/flutter/issues/new/choose
To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622
Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
androidseb pushed a commit to androidseb/packages that referenced this pull request Jun 8, 2025
…ak-fix] (flutter#8373)
The package manipulates disposable objects. This PR
- Fixes some memory leaks.
- Activates leak testing to make sure disposable objects are correctly disposed.
See the documentation: https://github.com/dart-lang/leak_tracker/blob/main/doc%2Fleak_tracking%2FDETECT.md
FMorschel pushed a commit to FMorschel/packages that referenced this pull request Jun 9, 2025
…ak-fix] (flutter#8373)
The package manipulates disposable objects. This PR
- Fixes some memory leaks.
- Activates leak testing to make sure disposable objects are correctly disposed.
See the documentation: https://github.com/dart-lang/leak_tracker/blob/main/doc%2Fleak_tracking%2FDETECT.md
creatorpiyush pushed a commit to creatorpiyush/packages that referenced this pull request Jun 10, 2026
…ak-fix] (flutter#8373)
The package manipulates disposable objects. This PR
- Fixes some memory leaks.
- Activates leak testing to make sure disposable objects are correctly disposed.
See the documentation: https://github.com/dart-lang/leak_tracker/blob/main/doc%2Fleak_tracking%2FDETECT.md
bisor0627 pushed a commit to bisor0627/packages that referenced this pull request Jun 19, 2026
…ak-fix] (flutter#8373)
The package manipulates disposable objects. This PR
- Fixes some memory leaks.
- Activates leak testing to make sure disposable objects are correctly disposed.
See the documentation: https://github.com/dart-lang/leak_tracker/blob/main/doc%2Fleak_tracking%2FDETECT.md
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: leak trackingIssues and PRs related to memory leaks detected by leak_trackerautosubmitMerge PR when tree becomes green via auto submit Appp: vector_graphics

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@ValentinVignal@jonahwilliams@polina-c