@@ -19,6 +19,15 @@ const int _kCanvasCacheSize = 30;
19
19
/// Canvases available for reuse, capped at [_kCanvasCacheSize] .
20
20
final List <BitmapCanvas > _recycledCanvases = < BitmapCanvas > [];
21
21
22
+ /// Reduces recycled canvas list by 50% to reduce bitmap canvas memory use.
23
+ void _reduceCanvasMemoryUsage () {
24
+ final int canvasCount = _recycledCanvases.length;
25
+ for (int i = 0 ; i < canvasCount; i++ ) {
26
+ _recycledCanvases[i].dispose ();
27
+ }
28
+ _recycledCanvases.clear ();
29
+ }
30
+
22
31
/// A request to repaint a canvas.
23
32
///
24
33
/// Paint requests are prioritized such that the larger pictures go first. This
@@ -42,22 +51,27 @@ class _PaintRequest {
42
51
List <_PaintRequest > _paintQueue = < _PaintRequest > [];
43
52
44
53
void _recycleCanvas (EngineCanvas canvas) {
45
- if (canvas is BitmapCanvas && canvas.isReusable ()) {
46
- _recycledCanvases.add (canvas);
47
- if (_recycledCanvases.length > _kCanvasCacheSize) {
48
- final BitmapCanvas removedCanvas = _recycledCanvases.removeAt (0 );
49
- removedCanvas.dispose ();
54
+ if (canvas is BitmapCanvas ) {
55
+ if (canvas.isReusable ()) {
56
+ _recycledCanvases.add (canvas);
57
+ if (_recycledCanvases.length > _kCanvasCacheSize) {
58
+ final BitmapCanvas removedCanvas = _recycledCanvases.removeAt (0 );
59
+ removedCanvas.dispose ();
60
+ if (_debugShowCanvasReuseStats) {
61
+ DebugCanvasReuseOverlay .instance.disposedCount++ ;
62
+ }
63
+ }
50
64
if (_debugShowCanvasReuseStats) {
51
- DebugCanvasReuseOverlay .instance.disposedCount++ ;
65
+ DebugCanvasReuseOverlay .instance.inRecycleCount =
66
+ _recycledCanvases.length;
52
67
}
53
- }
54
- if (_debugShowCanvasReuseStats) {
55
- DebugCanvasReuseOverlay .instance.inRecycleCount =
56
- _recycledCanvases.length;
68
+ } else {
69
+ canvas.dispose ();
57
70
}
58
71
}
59
72
}
60
73
74
+
61
75
/// Signature of a function that instantiates a [PersistedPicture] .
62
76
typedef PersistedPictureFactory = PersistedPicture Function (
63
77
double dx,
@@ -272,7 +286,6 @@ class PersistedStandardPicture extends PersistedPicture {
272
286
final ui.Size canvasSize = bounds.size;
273
287
BitmapCanvas bestRecycledCanvas;
274
288
double lastPixelCount = double .infinity;
275
-
276
289
for (int i = 0 ; i < _recycledCanvases.length; i++ ) {
277
290
final BitmapCanvas candidate = _recycledCanvases[i];
278
291
if (! candidate.isReusable ()) {
@@ -286,13 +299,21 @@ class PersistedStandardPicture extends PersistedPicture {
286
299
final bool fits = candidate.doesFitBounds (bounds);
287
300
final bool isSmaller = candidatePixelCount < lastPixelCount;
288
301
if (fits && isSmaller) {
289
- bestRecycledCanvas = candidate;
290
- lastPixelCount = candidatePixelCount;
291
- final bool fitsExactly = candidateSize.width == canvasSize.width &&
292
- candidateSize.height == canvasSize.height;
293
- if (fitsExactly) {
294
- // No need to keep looking any more.
295
- break ;
302
+ // [isTooSmall] is used to make sure that a small picture doesn't
303
+ // reuse and hold onto memory of a large canvas.
304
+ final double requestedPixelCount = bounds.width * bounds.height;
305
+ final bool isTooSmall = isSmaller &&
306
+ requestedPixelCount > 1 &&
307
+ (candidatePixelCount / requestedPixelCount) > 4 ;
308
+ if (! isTooSmall) {
309
+ bestRecycledCanvas = candidate;
310
+ lastPixelCount = candidatePixelCount;
311
+ final bool fitsExactly = candidateSize.width == canvasSize.width &&
312
+ candidateSize.height == canvasSize.height;
313
+ if (fitsExactly) {
314
+ // No need to keep looking any more.
315
+ break ;
316
+ }
296
317
}
297
318
}
298
319
}
0 commit comments