Why Does Mono Memory Keep Increasing While Managed Objects Stay Flat?
We’ve recently been investigating Mono memory issues in our project. In the GOT Online Mono Mode report from GameOptim, we observed that managed heap fragmentation keeps increasing over time, while the total amount of Managed Objects shows almost no growth. What usually causes this kind of behavior?
A good starting point is to check the Heap Object Snapshot section in the GOT Online Mono Mode report and look at the fragmentation ratio. It’s important to understand that an increase in Mono memory does not necessarily mean that resident objects are growing. It may also indicate that heap fragmentation is increasing. In the Mono Mode report: Used Mono = Managed Objects actual live objects + Heap Fragmentation These two parts are displayed separately in the Heap Object Snapshot : Pink represents Managed Objects Blue represents memory fragmentation https://uwa overseas public.oss us east 1.aliyuncs.com/uploads/markdown/438dfa17 8f13 4b65 a09c c203b43ae028.png From this report, we can see that Used Mono keeps rising continuously between frame 15000 and 20000 . Following the usual troubleshooting process, the first step is typically to inspect resident objects and check for memory leaks. However, after further analysis, we found that resident objects did not show any growth matching the increasing trend. By breaking down the composition of Used Mono, it becomes clear that the actual increase is not coming from Managed Objects, but from heap fragmentation . https://uwa overseas public.oss us east 1.aliyuncs.com/uploads/markdown/03609c12 02e9 40c4 b6ab 7810bdd054fe.png The judgment criteria are straightforward: If the Managed Object curve remains relatively stable , while Used Mono keeps increasing and the fragmentation ratio continues expanding , the problem is very likely not a memory leak, but heap fragmentation caused by frequent allocations. This is one of the typical characteristics of the Mono heap: The Mono heap usually expands on demand, but once heap space has been allocated, it generally does not immediately return to the operating system after objects are released. When a project frequently performs small object allocate → release operations, even if the total Managed Object count does not change much, it can still leave behind many fragmented free regions that cannot be continuously reused. As fragmentation accumulates, the Mono heap keeps expanding, which eventually pushes up Used Mono. In some projects, fragmentation can even approach a 1:1 ratio with actual Managed Objects. For example: Actual Managed Objects: ~200 MB Final Used Mono: nearly 400 MB In this situation, the focus should not be on who failed to release memory , but rather on who is allocating too frequently . Common sources of fragmentation include: LINQ allocations String concatenation Boxing / unboxing Coroutine closures Temporary Lists Frequent delegate creation So when Mono memory keeps increasing, don’t rush to conclude that there’s a memory leak. First, break down the composition of Used Mono and clearly distinguish whether the growth is caused by actual object growth or fragmentation growth. Only then can you decide the correct optimization direction.