Skip to content

Commit 2534ffe

Browse files
committed
Fix various memory leaks, see #925
1 parent f976794 commit 2534ffe

File tree

20 files changed

+450
-440
lines changed

20 files changed

+450
-440
lines changed

api/pubspec.lock

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ packages:
4545
dependency: transitive
4646
description:
4747
name: bloc
48-
sha256: "52c10575f4445c61dd9e0cafcc6356fdd827c4c64dd7945ef3c4105f6b6ac189"
48+
sha256: e18b8e7825e9921d67a6d256dba0b6015ece8a577eb0a411845c46a352994d78
4949
url: "https://pub.dev"
5050
source: hosted
51-
version: "9.0.0"
51+
version: "9.0.1"
5252
boolean_selector:
5353
dependency: transitive
5454
description:
@@ -61,10 +61,10 @@ packages:
6161
dependency: transitive
6262
description:
6363
name: build
64-
sha256: "5b887c55a0f734b433b3b2d89f9cd1f99eb636b17e268a5b4259258bc916504b"
64+
sha256: dfb67ccc9a78c642193e0c2d94cb9e48c2c818b3178a86097d644acdcde6a8d9
6565
url: "https://pub.dev"
6666
source: hosted
67-
version: "4.0.0"
67+
version: "4.0.2"
6868
build_config:
6969
dependency: transitive
7070
description:
@@ -85,10 +85,10 @@ packages:
8585
dependency: "direct dev"
8686
description:
8787
name: build_runner
88-
sha256: "804c47c936df75e1911c19a4fb8c46fa8ff2b3099b9f2b2aa4726af3774f734b"
88+
sha256: "4e54dbeefdc70691ba80b3bce3976af63b5425c8c07dface348dfee664a0edc1"
8989
url: "https://pub.dev"
9090
source: hosted
91-
version: "2.8.0"
91+
version: "2.9.0"
9292
built_collection:
9393
dependency: transitive
9494
description:
@@ -607,10 +607,10 @@ packages:
607607
dependency: transitive
608608
description:
609609
name: watcher
610-
sha256: "5bf046f41320ac97a469d506261797f35254fa61c641741ef32dacda98b7d39c"
610+
sha256: "592ab6e2892f67760543fb712ff0177f4ec76c031f02f5b4ff8d3fc5eb9fb61a"
611611
url: "https://pub.dev"
612612
source: hosted
613-
version: "1.1.3"
613+
version: "1.1.4"
614614
web:
615615
dependency: transitive
616616
description:

app/lib/bloc/document_bloc.dart

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -55,23 +55,29 @@ Future<(NoteData, List<PadElement>)> importAssetsAsync(
5555
void Function(String source)? onInvalidate,
5656
Map<String, String>? alreadyImported,
5757
Map<String, Uint8List>? assets,
58-
}) {
58+
}) async {
5959
ReceivePort? port;
60-
if (onInvalidate != null) {
61-
port = ReceivePort();
62-
port.listen((message) {
63-
if (message is String) {
64-
onInvalidate(message);
65-
}
66-
});
60+
StreamSubscription? subscription;
61+
try {
62+
if (onInvalidate != null) {
63+
port = ReceivePort();
64+
subscription = port.listen((message) {
65+
if (message is String) {
66+
onInvalidate(message);
67+
}
68+
});
69+
}
70+
return await compute(_importAssetsSync, (
71+
data,
72+
elements,
73+
onInvalidate: port?.sendPort,
74+
alreadyImported: alreadyImported,
75+
assets: assets,
76+
));
77+
} finally {
78+
await subscription?.cancel();
79+
port?.close();
6780
}
68-
return compute(_importAssetsSync, (
69-
data,
70-
elements,
71-
onInvalidate: port?.sendPort,
72-
alreadyImported: alreadyImported,
73-
assets: assets,
74-
));
7581
}
7682

7783
class DocumentBloc extends ReplayBloc<DocumentEvent, DocumentState> {

app/lib/cubits/current_index.dart

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,7 +1007,12 @@ class CurrentIndexCubit extends Cubit<CurrentIndex> {
10071007
).paint(canvas, size);
10081008

10091009
final picture = recorder.endRecording();
1010-
final newImage = await picture.toImage(imageWidth, imageHeight);
1010+
ui.Image newImage;
1011+
try {
1012+
newImage = await picture.toImage(imageWidth, imageHeight);
1013+
} finally {
1014+
picture.dispose();
1015+
}
10111016

10121017
var belowLayerImage = cameraViewport.belowLayerImage;
10131018
var aboveLayerImage = cameraViewport.aboveLayerImage;
@@ -1062,12 +1067,19 @@ class CurrentIndexCubit extends Cubit<CurrentIndex> {
10621067
renderBaked: false,
10631068
).paint(aboveLayerCanvas, size);
10641069

1065-
final result = await Future.wait([
1066-
belowLayerRecorder.endRecording().toImage(imageWidth, imageHeight),
1067-
aboveLayerRecorder.endRecording().toImage(imageWidth, imageHeight),
1068-
]);
1069-
belowLayerImage = result[0];
1070-
aboveLayerImage = result[1];
1070+
final belowPicture = belowLayerRecorder.endRecording();
1071+
final abovePicture = aboveLayerRecorder.endRecording();
1072+
try {
1073+
final result = await Future.wait([
1074+
belowPicture.toImage(imageWidth, imageHeight),
1075+
abovePicture.toImage(imageWidth, imageHeight),
1076+
]);
1077+
belowLayerImage = result[0];
1078+
aboveLayerImage = result[1];
1079+
} finally {
1080+
belowPicture.dispose();
1081+
abovePicture.dispose();
1082+
}
10711083
}
10721084

10731085
final newlyUnbaked =
@@ -1133,8 +1145,16 @@ class CurrentIndexCubit extends Cubit<CurrentIndex> {
11331145
);
11341146
painter.paint(canvas, Size(realWidth.toDouble(), realHeight.toDouble()));
11351147
final picture = recorder.endRecording();
1136-
final image = await picture.toImage(realWidth, realHeight);
1137-
return await image.toByteData(format: ui.ImageByteFormat.png);
1148+
ui.Image? image;
1149+
ByteData? bytes;
1150+
try {
1151+
image = await picture.toImage(realWidth, realHeight);
1152+
bytes = await image.toByteData(format: ui.ImageByteFormat.png);
1153+
} finally {
1154+
image?.dispose();
1155+
picture.dispose();
1156+
}
1157+
return bytes;
11381158
}
11391159

11401160
XmlDocument renderSVG(

app/lib/dialogs/background/dialog.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ class _BackgroundDialogState extends State<BackgroundDialog>
5858
});
5959
}
6060

61+
@override
62+
void dispose() {
63+
_tabController.dispose();
64+
super.dispose();
65+
}
66+
6167
@override
6268
Widget build(BuildContext context) {
6369
final loc = AppLocalizations.of(context);

app/lib/dialogs/background/general.dart

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -46,18 +46,22 @@ class _GeneralBackgroundPropertiesView extends StatelessWidget {
4646
if (result == null) return;
4747
final dataPath = Uri.dataFromBytes(result).toString();
4848
final codec = await ui.instantiateImageCodec(result);
49-
final frame = await codec.getNextFrame();
50-
final image = frame.image;
51-
final width = image.width.toDouble(),
52-
height = image.height.toDouble();
53-
image.dispose();
54-
onChanged(
55-
ImageBackground(
56-
source: dataPath,
57-
width: width,
58-
height: height,
59-
),
60-
);
49+
try {
50+
final frame = await codec.getNextFrame();
51+
final image = frame.image;
52+
final width = image.width.toDouble(),
53+
height = image.height.toDouble();
54+
image.dispose();
55+
onChanged(
56+
ImageBackground(
57+
source: dataPath,
58+
width: width,
59+
height: height,
60+
),
61+
);
62+
} finally {
63+
codec.dispose();
64+
}
6165
},
6266
),
6367
BoxTile(
@@ -76,13 +80,21 @@ class _GeneralBackgroundPropertiesView extends StatelessWidget {
7680
SvgStringLoader(contentString),
7781
null,
7882
);
79-
final size = info.size;
80-
var height = size.height, width = size.width;
81-
if (!height.isFinite) height = 0;
82-
if (!width.isFinite) width = 0;
83-
onChanged(
84-
SvgBackground(source: dataPath, width: width, height: height),
85-
);
83+
try {
84+
final size = info.size;
85+
var height = size.height, width = size.width;
86+
if (!height.isFinite) height = 0;
87+
if (!width.isFinite) width = 0;
88+
onChanged(
89+
SvgBackground(
90+
source: dataPath,
91+
width: width,
92+
height: height,
93+
),
94+
);
95+
} finally {
96+
info.picture.dispose();
97+
}
8698
},
8799
),
88100
],

app/lib/dialogs/file_system/create.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ class _FileSystemAssetCreateDialogState
2828

2929
@override
3030
void dispose() {
31-
super.dispose();
3231
_nameController.dispose();
32+
super.dispose();
3333
}
3434

3535
@override

app/lib/dialogs/file_system/move.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ class _FileSystemAssetMoveDialogState extends State<FileSystemAssetMoveDialog> {
3737

3838
@override
3939
void dispose() {
40-
super.dispose();
4140
_nameController.dispose();
41+
super.dispose();
4242
}
4343

4444
bool isSingleFile() => widget.assets.length == 1;

app/lib/dialogs/import/add.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ class _AddDialogState extends State<AddDialog> {
2727

2828
@override
2929
void dispose() {
30-
super.dispose();
3130
_searchController.dispose();
3231
_filterScrollController.dispose();
32+
super.dispose();
3333
}
3434

3535
@override
@@ -370,8 +370,8 @@ class _ToolsListViewState extends State<_ToolsListView> {
370370

371371
@override
372372
void dispose() {
373-
super.dispose();
374373
_scrollController.dispose();
374+
super.dispose();
375375
}
376376

377377
@override

app/lib/dialogs/packs/asset.dart

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -169,13 +169,19 @@ Future<void> addToPack(
169169
),
170170
),
171171
);
172-
final transformed = renderers
173-
.map(
174-
(e) =>
175-
e.transform(position: -rect.center, relative: true)?.element ??
176-
e.element,
177-
)
178-
.toList();
172+
final transformed = <PadElement>[];
173+
for (final renderer in renderers) {
174+
final transformedRenderer = renderer.transform(
175+
position: -rect.center,
176+
relative: true,
177+
);
178+
final activeRenderer = transformedRenderer ?? renderer;
179+
transformed.add(activeRenderer.element);
180+
transformedRenderer?.dispose();
181+
if (!identical(transformedRenderer, renderer)) {
182+
renderer.dispose();
183+
}
184+
}
179185
pack = pack.setComponent(
180186
result.key,
181187
ButterflyComponent(elements: transformed, thumbnail: thumbnail),

app/lib/models/defaults.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ class DocumentDefaults {
2828
size.height.toInt(),
2929
);
3030
final bytes = await image.toByteData(format: ui.ImageByteFormat.png);
31+
image.dispose();
32+
picture.dispose();
3133
return bytes!.buffer.asUint8List();
3234
}
3335

0 commit comments

Comments
 (0)