Practical Investigation of Memory Leaks in Flutter – Image Instance Case Study
The article describes how the MOO app team used Flutter's Dart VM Observatory and Allocation Profile tools to detect and fix an image memory leak caused by a custom painter not deregistering an ImageStreamListener, demonstrating step-by-step snapshot comparison, reference‑chain analysis, and the resulting memory stabilization after code fix.
MOO Music is a new music service under TME, and its team is one of the earliest adopters of Flutter within the company.
This series extracts the situations encountered during MOO APP development, focusing on Flutter memory‑usage management, and shares basic concepts, key points, troubleshooting methods, and optimization solutions. The memory‑management series is divided into three parts (upper, middle, lower); this article is the middle part.
4. Practical Investigation of Memory Leaks
To locate the problematic code, Android Studio or VS Code plugins wrap the relevant memory tools, which are built on the Dart VM service interfaces exposed in debug mode. The Dart VM service itself provides a tool – Dart VM Observatory – that can be accessed via the service’s HTTP link. The memory‑inspection path is: Isolate (main) → Allocation Profile.
With the tools ready, how do we pinpoint the code that causes the leak?
Repeatedly enter and exit the same feature or page.
Force a garbage collection (GC) and examine memory snapshots after each operation.
Compare the increase in object instances related to that feature.
If, after a forced GC, instances only increase or objects that should have been reclaimed remain, the associated code is likely problematic.
Below we take an Image memory‑leak investigation as an example, aiming to locate leaks in list‑item memory where list items are dynamically created and destroyed as the user scrolls.
1. We open a page in the app (e.g., a list page) and observe the initial overall memory of 470 MB in Xcode, as shown in Figure 1.
Figure 1
Scrolling down several pages causes memory to keep rising; the continuous increase indicates a memory‑leak problem, as shown in Figure 2.
Figure 2
2. Open the built‑in Allocation Profile tool and click the GC button at the top right to force the collection of all reclaimable objects (Figure 3).
Figure 3
After the forced collection, the remaining snapshot represents the strongly reachable objects in the current Isolate.
3. Comparing the initial snapshot with the current one (Figures 4 and 5) reveals a clear increase in Image instances, which continues to grow with scrolling and eventually exceeds the image‑cache size limit.
Figure 4
Figure 5
From this we can confirm that Image objects have references that are not being released. The next step is to find the owning objects that hold these Image references.
4. Click the Image link (Figure 6).
Figure 6
In the new page, expand the “strongly reachable” section to see the list of Image objects in the snapshot (Figure 7).
Figure 7
5. Open the Image instance detail view (Figure 8).
Figure 8
6. Search for nodes where the object reference is not released. The Image instance is ultimately referenced by _CacheImage , which is a normal cache reference.
According to the LRU mechanism of the image cache, some Image instances may be released from the cache but still held by other objects, so we continue to investigate other Image instances.
7. Randomly inspecting several Image instances yields clues (Figure 9).
Figure 9
This Image instance has been released by ImageCache but was not reclaimed.
8. The reference chain shows that DisplayDecorationImagePainter (a custom class) holds an ImageStreamListener , which in turn retains the Image object, causing the leak.
9. Reviewing the code reveals that DisplayDecorationImagePainter does not deregister the listener from the ImageStream during disposal.
10. After adding the deregistration code, repeating the scrolling test shows the Image instance count stabilizing around 122 MB and memory no longer grows (Figure 10).
Figure 10
At this point, the image‑memory issue is resolved.
The investigation process consists of tracing the reference chain of object instances to find code clues. For image leaks, setting a smaller image‑cache threshold can reduce the number of cached objects, making the investigation more efficient.
Leak investigation is a frequent, repetitive task. The built‑in tools lack good filtering for specific objects and have long operation paths with non‑intuitive reference‑chain displays. Developing a custom investigation tool could improve efficiency.
Tencent Music Tech Team
Public account of Tencent Music's development team, focusing on technology sharing and communication.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.