Why Does Unity Trigger Frequent GC Even When GC.Collect Isn't Called?
We found that some devices start experiencing unusually frequent GC after the game has been running for a while. However, our project never explicitly calls GC.Collect , and we don't see any obvious large memory allocations. What usually causes this issue, and how should we diagnose and optimize it? https://uwa overseas public.oss us east 1.aliyuncs.com/uploads/markdown/f1f9cd29 5548 4d1c 923d f267d4af189d.png
Frequent GC is not necessarily caused by explicit calls. In most Unity projects, it is triggered because the application continuously creates temporary managed objects during runtime. Over time, these allocations increase managed memory pressure until the garbage collector is forced to reclaim memory. It's also important to consider Incremental GC . When Incremental GC is enabled, Unity spreads garbage collection across multiple frames. As a result, you may observe more GC events but shorter GC pauses . Therefore, GC count alone is not a reliable indicator—GC duration and overall runtime performance should be evaluated together. Why can GC happen without calling ? In Unity, garbage collection is usually automatic rather than manually triggered. Even if your gameplay code never calls , frequent allocation of temporary managed objects can eventually force the runtime to perform garbage collection. Instead of asking "Is GC being called?" , the more useful question is: Which code path continuously creates managed objects? How should you diagnose frequent GC? A practical approach is to first review the GameOptim GOT Online report and identify when GC activity becomes concentrated. After locating the time window, correlate it with gameplay behavior. For example: Is GC occurring during combat ticks? Does it coincide with frequent UI updates? Is it triggered by another high frequency gameplay system? If GC spikes consistently overlap with a specific system, inspect the managed allocations generated by that execution path. What are the most common causes? In production projects, one of the most common reasons is that high frequency code continuously creates temporary objects. String concatenation is a typical example: Although each allocation is small, executing this statement every frame—or inside a Tick or Update loop—creates a new string object every time. Over long play sessions, these repeated allocations increase managed memory usage and eventually cause garbage collection to occur more frequently. What should you optimize? Instead of focusing only on GC count, analyze the following together: When GC is triggered Managed memory growth over time The gameplay logic running during those moments The primary optimization goal is to reduce temporary allocations on hot execution paths. Typical improvements include: Avoid creating objects inside or Tick loops. Cache reusable strings or constant text. Minimize unnecessary string concatenation and formatting. Reduce managed allocations in frequently executed code.