-
Notifications
You must be signed in to change notification settings - Fork 6k
Instrument Image and Picture for leak tracking. #35274
Changes from 21 commits
eb5cc0e
401a169
d6df6b8
eaf2ec8
3e17cd1
b47c31e
427592e
dbe4eaf
804d542
1434af9
60a95a0
e2a1f76
ca99635
1f85ecf
4a3d810
b577107
1e902a1
b6ff393
f03e228
6832d11
2ef20d0
932932f
4ea889e
0f53a5b
c9df53e
3f258cd
f951116
7940b1e
cc9912f
5ae80a6
ba7d0a5
7fec23d
9a8de06
22babb6
fca82fe
41754ed
4b24628
59cb250
0efa9c8
62431c1
a958c1d
20cd6d9
76f096e
6f949a2
f87653e
99ae37d
360ff2a
0da0e31
e972fd8
bf75813
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1649,12 +1649,27 @@ class Image { | |
| return true; | ||
| }()); | ||
| _image._handles.add(this); | ||
| onCreate?.call(this); | ||
| } | ||
|
|
||
| // C++ unit tests access this. | ||
| @pragma('vm:entry-point') | ||
| final _Image _image; | ||
|
|
||
| /// A callback that is invoked to report an object creation. | ||
| /// | ||
| /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart | ||
| /// than to use [onCreate] directly because [MemoryAllocations] | ||
| /// allows multiple callbacks. | ||
| static void Function(Image)? onCreate; | ||
polina-c marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| /// A callback that is invoked to report the object disposal. | ||
polina-c marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /// | ||
| /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart | ||
| /// than to use [onDispose] directly because [MemoryAllocations] | ||
| /// allows multiple callbacks. | ||
| static void Function(Image)? onDispose; | ||
|
|
||
| StackTrace? _debugStack; | ||
|
|
||
| /// The number of image pixels along the image's horizontal axis. | ||
|
|
@@ -1675,6 +1690,7 @@ class Image { | |
| /// useful when trying to determine what parts of the program are keeping an | ||
| /// image resident in memory. | ||
| void dispose() { | ||
| onDispose?.call(this); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here and elsewhere: can we guard calling these so it's compiled out of release mode?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As I know there is no compile time flags (like bool.fromEnvironment('flutter.memory_allocations')) in engine.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Discussed offline - any flag we put in here would be at best a runtime check that's probably no faster than the null check here. |
||
| assert(!_disposed && !_image._disposed); | ||
| assert(_image._handles.contains(this)); | ||
| _disposed = true; | ||
|
|
@@ -5591,7 +5607,21 @@ class Picture extends NativeFieldWrapperClass1 { | |
| /// | ||
| /// To create a [Picture], use a [PictureRecorder]. | ||
| @pragma('vm:entry-point') | ||
| Picture._(); | ||
| Picture._() { onCreate?.call(this); } | ||
polina-c marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| /// A callback that is invoked to report an object creation. | ||
polina-c marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /// | ||
| /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart | ||
| /// than to use [onCreate] directly because [MemoryAllocations] | ||
| /// allows multiple callbacks. | ||
| static void Function(Picture)? onCreate; | ||
|
|
||
| /// A callback that is invoked to report the object disposal. | ||
polina-c marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /// | ||
| /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart | ||
| /// than to use [onDispose] directly because [MemoryAllocations] | ||
| /// allows multiple callbacks. | ||
| static void Function(Picture)? onDispose; | ||
|
|
||
| /// Creates an image from this picture. | ||
| /// | ||
|
|
@@ -5656,6 +5686,7 @@ class Picture extends NativeFieldWrapperClass1 { | |
| _disposed = true; | ||
| return true; | ||
| }()); | ||
| onDispose?.call(this); | ||
| _dispose(); | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| // Copyright 2013 The Flutter Authors. All rights reserved. | ||
| // Use of this source code is governed by a BSD-style license that can be | ||
| // found in the LICENSE file. | ||
|
|
||
| import 'package:test/test.dart'; | ||
| import 'package:ui/ui.dart'; | ||
|
|
||
| void main() { | ||
| test('Image constructor invokes onCreate once', () async { | ||
| int onCreateInvokedCount = 0; | ||
| Image? createdImage; | ||
| Image.onCreate = (Image image) { | ||
| onCreateInvokedCount++; | ||
| createdImage = image; | ||
| }; | ||
|
|
||
| final Image image1 = await _createImage(); | ||
|
|
||
| expect(onCreateInvokedCount, 1); | ||
| expect(createdImage, image1); | ||
|
|
||
| final Image image2 = await _createImage(); | ||
|
|
||
| expect(onCreateInvokedCount, 2); | ||
| expect(createdImage, image2); | ||
| Image.onCreate = null; | ||
| }); | ||
|
|
||
| test('dispose() invokes onDispose once', () async { | ||
| int onDisposeInvokedCount = 0; | ||
| Image? disposedImage; | ||
| Image.onDispose = (Image image) { | ||
| onDisposeInvokedCount++; | ||
| disposedImage = image; | ||
| }; | ||
|
|
||
| final Image image1 = await _createImage()..dispose(); | ||
|
|
||
| expect(onDisposeInvokedCount, 1); | ||
| expect(disposedImage, image1); | ||
|
|
||
| final Image image2 = await _createImage()..dispose(); | ||
|
|
||
| expect(onDisposeInvokedCount, 2); | ||
| expect(disposedImage, image2); | ||
|
|
||
| Image.onDispose = null; | ||
| }); | ||
| } | ||
|
|
||
|
|
||
| Future<Image> _createImage() async => _createPicture().toImage(10, 10); | ||
|
|
||
| Picture _createPicture() { | ||
| final PictureRecorder recorder = PictureRecorder(); | ||
| final Canvas canvas = Canvas(recorder); | ||
| const Rect rect = Rect.fromLTWH(0.0, 0.0, 100.0, 100.0); | ||
| canvas.clipRect(rect); | ||
| return recorder.endRecording(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| // Copyright 2013 The Flutter Authors. All rights reserved. | ||
| // Use of this source code is governed by a BSD-style license that can be | ||
| // found in the LICENSE file. | ||
|
|
||
| import 'package:test/test.dart'; | ||
| import 'package:ui/ui.dart'; | ||
|
|
||
| void main() { | ||
| test('Picture constructor invokes onCreate once', () async { | ||
| int onCreateInvokedCount = 0; | ||
| Picture? createdPicture; | ||
| Picture.onCreate = (Picture picture) { | ||
| onCreateInvokedCount++; | ||
| createdPicture = picture; | ||
| }; | ||
|
|
||
| final Picture picture1 = _createPicture(); | ||
|
|
||
| expect(onCreateInvokedCount, 1); | ||
| expect(createdPicture, picture1); | ||
|
|
||
| final Picture picture2 = _createPicture(); | ||
|
|
||
| expect(onCreateInvokedCount, 2); | ||
| expect(createdPicture, picture2); | ||
| Picture.onCreate = null; | ||
| }); | ||
|
|
||
| test('dispose() invokes onDispose once', () async { | ||
| int onDisposeInvokedCount = 0; | ||
| Picture? disposedPicture; | ||
| Picture.onDispose = (Picture picture) { | ||
| onDisposeInvokedCount++; | ||
| disposedPicture = picture; | ||
| }; | ||
|
|
||
| final Picture picture1 = _createPicture()..dispose(); | ||
|
|
||
| expect(onDisposeInvokedCount, 1); | ||
| expect(disposedPicture, picture1); | ||
|
|
||
| final Picture picture2 = _createPicture()..dispose(); | ||
|
|
||
| expect(onDisposeInvokedCount, 2); | ||
| expect(disposedPicture, picture2); | ||
|
|
||
| Picture.onDispose = null; | ||
| }); | ||
| } | ||
|
|
||
| Picture _createPicture() { | ||
| final PictureRecorder recorder = PictureRecorder(); | ||
| final Canvas canvas = Canvas(recorder); | ||
| const Rect rect = Rect.fromLTWH(0.0, 0.0, 100.0, 100.0); | ||
| canvas.clipRect(rect); | ||
| return recorder.endRecording(); | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.