@@ -19,6 +19,15 @@ const int _kCanvasCacheSize = 30;
1919/// Canvases available for reuse, capped at [_kCanvasCacheSize] .
2020final List <BitmapCanvas > _recycledCanvases = < BitmapCanvas > [];
2121
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+
2231/// A request to repaint a canvas.
2332///
2433/// Paint requests are prioritized such that the larger pictures go first. This
@@ -42,22 +51,27 @@ class _PaintRequest {
4251List <_PaintRequest > _paintQueue = < _PaintRequest > [];
4352
4453void _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+ }
5064 if (_debugShowCanvasReuseStats) {
51- DebugCanvasReuseOverlay .instance.disposedCount++ ;
65+ DebugCanvasReuseOverlay .instance.inRecycleCount =
66+ _recycledCanvases.length;
5267 }
53- }
54- if (_debugShowCanvasReuseStats) {
55- DebugCanvasReuseOverlay .instance.inRecycleCount =
56- _recycledCanvases.length;
68+ } else {
69+ canvas.dispose ();
5770 }
5871 }
5972}
6073
74+
6175/// Signature of a function that instantiates a [PersistedPicture] .
6276typedef PersistedPictureFactory = PersistedPicture Function (
6377 double dx,
@@ -272,7 +286,6 @@ class PersistedStandardPicture extends PersistedPicture {
272286 final ui.Size canvasSize = bounds.size;
273287 BitmapCanvas bestRecycledCanvas;
274288 double lastPixelCount = double .infinity;
275-
276289 for (int i = 0 ; i < _recycledCanvases.length; i++ ) {
277290 final BitmapCanvas candidate = _recycledCanvases[i];
278291 if (! candidate.isReusable ()) {
@@ -286,13 +299,21 @@ class PersistedStandardPicture extends PersistedPicture {
286299 final bool fits = candidate.doesFitBounds (bounds);
287300 final bool isSmaller = candidatePixelCount < lastPixelCount;
288301 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+ }
296317 }
297318 }
298319 }
0 commit comments