Unity memory leak learning summary

The definition of memory leak and its harm

1, Definition: A memory leak occurs when a program fails to release memory that is no longer in use due to negligence or error.
Memory leaks do not refer to the physical disappearance of memory, but after the application allocates a certain segment of memory, due to design errors, causes the memory to be released before it is released. You lose control of this segment of memory, resulting in a waste of memory.

2, Hazards: In the operating system, in order to avoid clearing when there is no memory to allocate, applications that do not return memory are usually Kill it. It can be seen from this that the danger and severity of memory leaks are If the leak continues, the application will crash due to excessive memory usage. Of course, leaks can also cause other hazards, such as memory being occupied by useless objects, causing subsequent memory allocation to require higher time costs, causing game lags, etc.

Memory leak in Unity

After having a preliminary understanding of memory leaks, let’s learn about memory leaks in the Unity environment.
Generally speaking, game programs are composed of two parts: code and resources. Memory leaks under Unity are mainly divided into Leaks on the code side. Of course, resource-side leaks are also caused by unreasonable references to resources in the code. leakage on the resource sideand

1. Leak on the code side - Mono memory leak

When developing with Unity, we should understand that Unity uses Mono-based C# as a scripting language (there are also other scripting languages, but they will not be discussed here). It is a memory management language based on the Garbage Collection (hereinafter referred to as GC) mechanism. .
GC explanation

principle

The garbage collector has two basic principles:
1. Consider that an object will not be accessed in future program execution.
2. Recycle the memory occupied by these objects.

Collector implementation

The following is an introduction to GC implementation from Wikipedia:
GC implementation

However, memory hosting itself is not omnipotent. What GC can do is to find "garbage" through a certain algorithm and automatically recycle the memory occupied by "garbage". To clarify this relationship, we must first understand what garbage is.

Q: What is garbage?
A: Combining the above introduction to the principles and implementation mechanisms of GC, we can roughly infer that, For GC, there are no referenced objects (objects) ), is "junk". Since there is no reference, it means that the target object has lost its use value for any other object, then it becomes "garbage" (same as real life, we put things that have no use value for us, become trash). Then according to the GC mechanism, the memory occupied will be recycled.

Understanding the meaning of garbage in GC, we can know that,From a computer perspective, when an object exceeds its scope, we forget to clean up the object. References to useless objects, this situation is a memory leak that occurs in a managed memory environment. This kind of leakage may appear to be very small in isolation, but in fact it has a profound impact on memory. Because in the actual code, memory is not allocated only when new is explicitly called. There are also many implicit allocations, such as generating a List array, caching data sent by the server, generating a string, etc. These operations will generate memory. distribution.

After extending GC to a certain extent, let’s return to Unity itself.In the Unity environment, the memory usage of the Mono heap will only increase but not decrease< /span>. Specifically, the Mono heap can be understood as a memory pool. Every application for Mono memory will be allocated in the pool; when it is released, it is also returned to the pool and not to the operating system. If it is found that there is not enough memory in the pool during a certain allocation, the pool will be expanded - applying to the operating system for more memory to expand the pool to meet the memory allocation. It should be noted that each expansion of the pool is a larger memory allocation. Each expansion will expand the pool by about 6-10M. Therefore, Mono memory leaks are a part that requires special attention in Unity game development.

2. Leakage on the resource side - Native memory leakage

Resource leakage: It means that the resource occupies memory after loading, but after the resource is not used, the resource is not unloaded, resulting in memory occupation.

Before discussing the causes of resource memory leaks, let's first take a look at Unity's resource management and recycling methods. The reason why resource memory and code memory should be discussed separately is because their memory management methods are different.

The memory allocated by the code mentioned above is allocated on Mono heap memory through the Mono virtual machine. . Memory allocated through the interface in the System namespace will be allocated in the Mono heap through the Mono Runtime;memory allocated through the interface in the UnityEngine namespace will be allocated in the Native heap through Unity. To give a simple example, Native heap memory, and its main purpose is for programmers to use it when processing program logic; Unity’s resources are allocated through Unity’s C++ layerThe memory footprint is generally small

Mono memory is reclaimed through GC, and Unity also provides a similar way to reclaim memory. The difference is that Unity's memory recycling needs to be actively triggered. The actively called interface isResources.UnloadUnusedAssets(). In fact, GC also provides the same interface **GC.Collect()** to actively trigger garbage collection. Both interfaces require a lot of calculations. We do not recommend actively calling them from time to time while the game is running. Generally, Generally speaking, in order to avoid game lags, it is recommended to handle garbage collection during the loading process. One thing that needs to be explained is that Resources.UnloadUnusedAssets() itself will call GC.Collect() internally. Unity also provides another more violent way - Resources.UnloadAsset() to unload resources, but this interface will directly delete the resource regardless of whether it is "junk" or not. , is a very dangerous interface. It is recommended to call this interface only after making sure that the resource is not in use.

Based on the above basic knowledge, let’s take a look at why there is resource leakage. First, like the leak on the code side, due to "There is an incorrect reference that should be released but is not released", the recycling mechanism thinks that the target object is not "garbage". So that it cannot be recycled, which is also the most common situation.

There is also a typical leak situation for resources. Since resource unloading is actively triggered, the timing of clearing references to resources is particularly important. The logic of the game now tends to become more complicated. At the same time, if a new member joins the project team, they may not be able to clearly understand the details of all resource management. If " is cleared after resource unloading is triggered, For resource references", memory leaks will also occur.

There is also a resource leak, because some interfaces of Unity will generate a copy when called (such as Renderer.Material referencehttps://docs.unity3d. com/ScriptReference/Renderer-material.html), if you are not careful in using it, more resource copies will be generated during runtime, resulting in unnecessary waste of memory. However, this type of memory copy generally has a small amount and is relatively simple to repair. I will not give a lengthy introduction here.

3. Avoid and fix memory leaks

We know that memory leaks can be avoided as long asunlocking the reference before recycling occurs, which seems to be a very simple problem. However, because the logical complexity of actual projects is often beyond imagination, the reference relationship is not a simple one or two layers (sometimes there are often as many as a dozen or even dozens of layers before connecting to the final reference object), and there may be intersections. In complex situations such as references and circular references, it is difficult to correctly resolve references purely from the perspective of code review. How to find the reference that causes the leak is the difficulty and focus of repairing the leak.

Common situations of memory leaks and how to avoid them

1. static keyword
All static/non-static member variables held by static instances need to be cleared in time, or the static instance can be cleared directly
Static member variables held by non-static instances need to be cleared in time
instance is not necessarily a clearing operation, it can also point to other instances, that is, instance = new InstanceClass()

2. Download Texture remotely
Download a texture Texture remotely and assign it to Image _img. This is also a situation that novices often ignore and can lead to memory overflow. The process of completely unloading memory should be like this:
(1) Select one of the following three options to disconnect the reference between Image and Texture, which can be selected according to business needs

  • The gameObject where Destroy_img is located is Destroy(_img.gameObject)
  • Destroy_img component is Destroy(_img)
  • Leave _img.sprite blank, that is, _img.sprite = null

(2) Leave the variable referenced to Image blank, that is, _img = null
(3) Of course, if the Texture is cached or the Sprite converted from the Texture is cached , you also need to make these cache references blank, that is, _tempSprite = null or _texDict.Clear() or _texDict = null
(4) Call Resources after executing the above steps in any order. UnloadunusedAsset() can completely unload the Texture from memory

3. Resources&Instantiate Gameobject
After calling Resources.Load to get the original, instantiate it to get the instance.
(1) Let’s talk about unloading the original memory first. Calling Resources.UnloadunusedAsset() can completely unload the original from the memory. Of course, if there is a variable referencing the original, before calling Resources.UnloadunusedAsset() , these references need to be left blank.

Therefore, if the original cannot be reused, it is recommended to define the original as a local variable so that its scope is within Start(). This writing method is more concise. When unloading original memory, just call Resources.UnloadUnusedAssets() directly.

This is more interesting. You can unload original without Destroy instance. This shows that the instance obtained after Instantiate does not have a "reference dependency" relationship with original.

(2) The above is the memory of unload original, and the next is the memory of unload instance.
For this part of memory, only Destroy(instance.gameObject) is needed to empty the variables that reference instance. Finally, call Resources.UnloadUnusedAssets() to unload the instance.

4. There are still some differences in the memory unload between the Gameobject originally existing in the scene and the Gameobject obtained by Resources Instantiate
.

(1) For example, for the former: there is a Cube in the scene. After Destroy(cube), calling Resources.UnloadUnusedAssets() can unload the memory of the Cube, but it cannot unload the resources referenced by the Cube. , so you also need to leave the resources referenced by the Cube blank, that is, leave the material blank, so that you can completely unload the Cube.
(2) If the latter wants to unload the memory, there is no need to empty the referenced resources.

5. Resources.UnloadAsset
Texture2D can be unloaded through this API, but TextAsset cannot.

Tools to fix memory leaks

Here are some recommended tools to troubleshoot and repair memory leaks:

1、Memory Profiler和New Memory Profiler For Unity5

First of all, Unity provides its own support in memory analysis tools. The open source memory visualization tool provided by Unity Bitbucket enables the best diagnosis of memory issues in Unity.
Specific link:
Memory Profiler
https://docs.unity3d.com/Manual/ProfilerMemory.htmlhttps://docs.unity.cn/cn/2019.4/Manual/BestPracticeUnderstandingPerformanceInUnity2.html
New Memory Profiler For Unity5

2. The magnifying glass of Mono memory——Cube

Cube is a performance indicator collection tool for Unity projects on the Tencent WeTest platform under Tencent Games. Through Cube, you can more easily obtain various performance indicators of the game, providing a direction for performance optimization. At the same time, Cube is also a good measurement tool for game performance.

4. Suggestions to avoid memory leaks

1. In terms of architecture, add more abstract interfaces for destruction to remind team members to pay attention to cleaning up the "garbage" they generate.
2. Strictly control the use of static and prohibit the use of static in unnecessary places.
3. Strengthen the concept of life cycle. Whether it is a code object or a resource, it has its own life cycle and will be released after the life cycle ends. If possible, the life cycle needs to be described in the functional design document.

Text summary:
1, http://t.csdn.cn/bv0Fo
2、http://t.csdn.cn/NZnxE

Guess you like

Origin blog.csdn.net/ProSWhite/article/details/132489284