Unity Prevent Singleton Manager From Being Instantiated Again

Stable scripting runtime: known limitations

Referencing boosted course library assemblies

Agreement Automatic Memory Management

When an object, string or assortment is created, the memory required to store it is allocated from a cardinal pool chosen the heap. When the detail is no longer in employ, the retention information technology one time occupied tin be reclaimed and used for something else. In the past, it was typically up to the programmer to allocate and release these blocks of heap memory explicitly with the advisable function calls. Nowadays, runtime systems like Unity's Mono engine manage memory for you lot automatically. Automatic memory direction requires less coding endeavor than explicit resource allotment/release and greatly reduces the potential for retentivity leakage (the situation where retentiveness is allocated only never subsequently released).

Value and Reference Types

When a part is called, the values of its parameters are copied to an area of retention reserved for that specific call. Data types that occupy only a few bytes tin can be copied very quickly and easily. However, it is common for objects, strings and arrays to exist much larger and it would be very inefficient if these types of data were copied on a regular basis. Fortunately, this is non necessary; the actual storage infinite for a large item is allocated from the heap and a pocket-size "pointer" value is used to recollect its location. From and so on, just the arrow need be copied during parameter passing. Every bit long every bit the runtime organisation can locate the item identified by the arrow, a single copy of the information can be used equally oftentimes as necessary.

Types that are stored straight and copied during parameter passing are chosen value types. These include integers, floats, booleans and Unity's struct types (eg, Color and Vector3). Types that are allocated on the heap then accessed via a arrow are called reference types, since the value stored in the variable merely "refers" to the real data. Examples of reference types include objects, strings and arrays.

Allocation and Garbage Collection

The memory manager keeps runway of areas in the heap that it knows to exist unused. When a new cake of retentiveness is requested (say when an object is instantiated), the manager chooses an unused surface area from which to classify the block and then removes the allocated memory from the known unused space. Subsequent requests are handled the aforementioned style until there is no free area large enough to allocate the required block size. It is highly unlikely at this point that all the memory allocated from the heap is still in use. A reference detail on the heap can only be accessed as long as there are however reference variables that can locate it. If all references to a retention block are gone (ie, the reference variables have been reassigned or they are local variables that are now out of scope) so the memory information technology occupies tin safely be reallocated.

To determine which heap blocks are no longer in use, the retention manager searches through all currently active reference variables and marks the blocks they refer to as "live". At the end of the search, whatsoever space between the alive blocks is considered empty by the retentiveness managing director and can be used for subsequent allocations. For obvious reasons, the process of locating and freeing up unused memory is known equally garbage drove (or GC for brusk).

Unity uses the Boehm–Demers–Weiser garbage collector, a stop-the-world garbage collector. Whenever Unity needs to perform garbage collection, information technology stops running your program code and only resumes normal execution when the garbage collector has finished all its piece of work. This interruption can cause delays in the execution of your game that last anywhere from less than 1 millisecond to hundreds of milliseconds, depending on how much memory the garbage collector needs to process and on the platform the game is running on. For real-time applications like games, this tin get quite a big issue, because y'all tin't sustain the consistent frame rate that smooth animation crave when the garbage collector suspends a game's execution. These interruptions are also known as GC spikes, because they testify as spikes in the Profiler frame time graph. In the next sections you tin can learn more most how to write your code to avert unnecessary garbage-collected memory allocations while running the game, so the garbage collector has less work to do.

Optimization

Garbage drove is automatic and invisible to the developer but the collection process really requires significant CPU time behind the scenes. When used correctly, automatic memory management will generally equal or beat manual allotment for overall performance. However, it is of import for the programmer to avoid mistakes that will trigger the collector more ofttimes than necessary and introduce pauses in execution.

In that location are some infamous algorithms that tin can be GC nightmares even though they seem innocent at first sight. Repeated cord concatenation is a classic example:

          //C# script example using UnityEngine; using System.Collections;  public class ExampleScript : MonoBehaviour {     void ConcatExample(int[] intArray) {         string line = intArray[0].ToString();                  for (i = ane; i < intArray.Length; i++) {             line += ", " + intArray[i].ToString();         }                  return line;     } }                  

The central detail here is that the new pieces don't get added to the string in place, ane by one. What actually happens is that each fourth dimension effectually the loop, the previous contents of the line variable become dead - a whole new string is allocated to comprise the original slice plus the new part at the end. Since the string gets longer with increasing values of i, the amount of heap space being consumed also increases and so it is piece of cake to use upwardly hundreds of bytes of free heap space each time this role is called. If you need to concatenate many strings together so a much amend option is the Mono library'due south Organisation.Text.StringBuilder class.

Still, even repeated concatenation won't cause too much trouble unless it is called oft, and in Unity that usually implies the frame update. Something like:

          //C# script example using UnityEngine; using UnityEngine.UI; using System.Collections;  public class ExampleScript : MonoBehaviour {     public Text scoreBoard;     public int score;          void Update() {         string scoreText = "Score: " + score.ToString();         scoreBoard.text = scoreText;     } }                  

…will allocate new strings each time Update is chosen and generate a constant trickle of new garbage. Most of that can be saved by updating the text only when the score changes:

          //C# script example using UnityEngine; using UnityEngine.UI; using System.Collections;  public grade ExampleScript : MonoBehaviour {     public Text scoreBoard;     public string scoreText;     public int score;     public int oldScore;          void Update() {         if (score != oldScore) {             scoreText = "Score: " + score.ToString();             scoreBoard.text = scoreText;             oldScore = score;         }     } }                  

Another potential problem occurs when a role returns an array value:

          //C# script case using UnityEngine; using System.Collections;  public grade ExampleScript : MonoBehaviour {     float[] RandomList(int numElements) {         var outcome = new float[numElements];                  for (int i = 0; i < numElements; i++) {             result[i] = Random.value;         }                  return issue;     } }                  

This type of office is very elegant and convenient when creating a new array filled with values. Notwithstanding, if information technology is called repeatedly then fresh memory will be allocated each time. Since arrays tin exist very large, the costless heap space could get used up rapidly, resulting in frequent garbage collections. One mode to avoid this trouble is to make use of the fact that an array is a reference type. An array passed into a function every bit a parameter tin exist modified within that function and the results volition remain later on the function returns. A function like the i above tin can often exist replaced with something similar:

          //C# script example using UnityEngine; using System.Collections;  public class ExampleScript : MonoBehaviour {     void RandomList(bladder[] arrayToFill) {         for (int i = 0; i < arrayToFill.Length; i++) {             arrayToFill[i] = Random.value;         }     } }                  

This simply replaces the existing contents of the array with new values. Although this requires the initial allotment of the array to be done in the calling code (which looks slightly inelegant), the function volition non generate any new garbage when information technology is called.

Disabling garbage collection

If you are using the Mono or IL2CPP A Unity-developed scripting dorsum-end which you can utilize equally an alternative to Mono when edifice projects for some platforms. More than info
Come across in Glossary
scripting backend A framework that powers scripting in Unity. Unity supports iii different scripting backends depending on target platform: Mono, .NET and IL2CPP. Universal Windows Platform, nonetheless, supports but two: .NET and IL2CPP. More info
Encounter in Glossary
, y'all can avert CPU spikes during garbage drove by disabling garbage collection at run time. When you disable garbage collection, retentivity usage never decreases because the garbage collector does not collect objects that no longer have any references. In fact, memory usage can simply always increment when you disable garbage drove. To avert increased memory usage over fourth dimension, take care when managing memory. Ideally, allocate all memory before you disable the garbage collector and avoid boosted allocations while it is disabled.

For more details on how to enable and disable garbage collection at run time, come across the GarbageCollector Scripting API folio.

Y'all can besides try an Incremental garbage collection option.

Requesting a Collection

As mentioned in a higher place, it is best to avoid allocations equally far as possible. Nonetheless, given that they tin can't exist completely eliminated, in that location are 2 principal strategies you can utilise to minimise their intrusion into gameplay.

Small heap with fast and frequent garbage collection

This strategy is often all-time for games that have long periods of gameplay where a smooth framerate is the principal concern. A game like this will typically classify small blocks often simply these blocks will be in employ but briefly. The typical heap size when using this strategy on iOS Apple tree's mobile operating system. More info
See in Glossary
is nigh 200KB and garbage drove will take about 5ms on an iPhone 3G. If the heap increases to 1MB, the drove will take about 7ms. It can therefore be advantageous sometimes to asking a garbage collection at a regular frame interval. This will generally make collections happen more oft than strictly necessary just they will be candy quickly and with minimal effect on gameplay:

          if (Time.frameCount % 30 == 0) {    System.GC.Collect(); }                  

Withal, you should utilise this technique with caution and bank check the profiler statistics to make sure that it is really reducing drove fourth dimension for your game.

Large heap with slow merely infrequent garbage drove

This strategy works best for games where allocations (and therefore collections) are relatively exceptional and can be handled during pauses in gameplay. It is useful for the heap to be as large equally possible without being so large equally to get your app killed by the Bone due to depression system memory. Even so, the Mono runtime avoids expanding the heap automatically if at all possible. You can aggrandize the heap manually by preallocating some placeholder space during startup (ie, you instantiate a "useless" object that is allocated purely for its effect on the memory manager):

          //C# script example using UnityEngine; using System.Collections;  public class ExampleScript : MonoBehaviour {     void Start() {         var tmp = new Arrangement.Object[1024];                  // make allocations in smaller blocks to avoid them to be treated in a special way, which is designed for large blocks         for (int i = 0; i < 1024; i++)             tmp[i] = new byte[1024];                  // release reference         tmp = null;     } }                  

A sufficiently large heap should not go completely filled up between those pauses in gameplay that would accommodate a collection. When such a suspension occurs, you lot can request a collection explicitly:

          Organisation.GC.Collect();                  

Again, y'all should take care when using this strategy and pay attention to the profiler statistics rather than simply bold it is having the desired effect.

Reusable Object Pools

In that location are many cases where you tin can avoid generating garbage but by reducing the number of objects that get created and destroyed. There are sure types of objects in games, such every bit projectiles, which may be encountered over and over once again fifty-fifty though merely a small number will ever exist in play at once. In cases like this, it is oft possible to reuse objects rather than destroy quondam ones and supplant them with new ones.

Incremental Garbage Collection

Incremental garbage collection spreads out the process of garbage drove over multiple frames.

Incremental garbage drove is the default garbage collection method Unity uses. This is notwithstanding the Boehm-Demers-Weiser garbage collector, only Unity runs it in an incremental mode. Instead of doing a total garbage collection each time it runs, Unity splits up the garbage collection workload over multiple frames. This means that instead of one long interruption to your program's execution to let the garbage collector to do its work, Unity makes multiple, much shorter interruptions. While this does not make garbage collection faster overall, distributing the workload over multiple frames can significantly reduce the trouble of garbage collection "spikes" that interruption the smoothness of your application.

The following screenshots from the Unity Profiler illustrate how incremental drove reduces framerate hiccups. In these profile traces, the light blue parts of the frame show how much time is used by script operations, the yellow parts show the time remaining in the frame until Vsync (waiting for the next frame to begin), and the dark light-green parts show the time spent for garbage collection.

The following screenshot displays a frame capture from the Unity Profiler in an application that does non use incremental garbage collection:

Profile without using incremental garbage collection
Profile without using incremental garbage collection

Without incremental garbage collection, a spike interrupts the otherwise smooth 60fps frame rate. This fasten pushes the frame in which garbage collection occurs well over the 16 millisecond limit required to maintain 60FPS (this example drops more than one frame because of garbage collection.)

The post-obit screenshot displays a frame capture from the Unity Profiler in an application that does use incremental garbage drove:

Incremental garbage collection profile
Incremental garbage collection profile

With incremental garbage drove enabled (to a higher place), the aforementioned project keeps its consequent 60fps frame charge per unit, as the garbage collection operation is broken up over several frames, using but a small-scale time slice of each frame (the darker green fringe just higher up the xanthous Vsync trace).

The following screenshot displays a frame capture in the Unity Profiler from the aforementioned projection, also running with incremental garbage collection enabled, merely this time with fewer scripting operations per frame.

Incremental garbage collection using left over time in frame
Incremental garbage collection using left over time in frame

Over again, the garbage collection operation is broken upward over several frames. The departure is that this fourth dimension, the garbage drove uses more time each frame, and requires fewer total frames to terminate. This is because Unity adjusts the time it allocates to garbage drove based on the remaining available frame time if your application uses VsyncVertical synchronization (VSync) is a display setting that caps a game'southward frame charge per unit to friction match the refresh charge per unit of a monitor, to prevent paradigm tearing. More than info
See in Glossary
or Application.targetFrameRate. This way, Unity can run the garbage collection in time it would otherwise spend waiting, and therefore carry out garbage drove with a minimal operation affect.

All platforms other than WebGL A JavaScript API that renders 2d and 3D graphics in a web browser. The Unity WebGL build option allows Unity to publish content as JavaScript programs which utilise HTML5 technologies and the WebGL rendering API to run Unity content in a web browser. More info
Encounter in Glossary
support incremental garbage collection.

Player Settings to disable incremental garbage collection
Actor Settings to disable incremental garbage collection

In addition, if you ready the VSync Count to anything other than Don't Sync (in your projection's Quality settings or with the Awarding.VSync belongings) or you enable the Awarding.targetFrameRate property, Unity automatically uses any idle time left at the end of a given frame for incremental garbage collection.

To exercise more precise control over incremental garbage drove behavior, you tin use the Scripting.GarbageCollector class. For example, if you lot do not want to use VSync or a target frame rate, you can summate the amount of fourth dimension available before the stop of a frame yourself, and provide that time to the garbage collector to use.

Possible problems with incremental collection

In nearly cases, incremental garbage collection can mitigate the problem of garbage collection spikes. Notwithstanding, in some cases, incremental garbage collection may not bear witness beneficial in practice.

When incremental garbage collection breaks up its piece of work, it breaks up the marking phase in which it scans all managed objects to determine which objects are yet in use and which objects can exist cleaned up. Dividing up the marking phase works well when most of the references between objects don't change between slices of work. When an object reference does change, those objects must exist scanned again in the next iteration. Thus, too many changes tin overwhelm the incremental garbage collector and cause a state of affairs where the marker pass never finishes considering it ever has more work to do – in this case, the garbage drove falls back to doing a full, non-incremental collection.

Likewise, when using incremental garbage drove, Unity needs to generate additional lawmaking (known equally write barriers) to inform the garbage drove whenever a reference has changed (so the garbage collection will know if it needs to rescan an object). This adds some overhead when changing references which tin have a measurable performance impact in some managed code.

Withal, most typical Unity projects (if there is such a affair equally a "typical" Unity project) can benefit from incremental garbage drove, specially if they suffer from garbage collection spikes.

Always use the ProfilerA window that helps you to optimize your game. Information technology shows how much time is spent in the various areas of your game. For example, it can study the percentage of time spent rendering, animative or in your game logic. More info
Come across in Glossary
to verify that your game or program performs as you expect.

Further Information

Memory management is a subtle and complex subject to which a nifty deal of academic effort has been devoted. If you are interested in learning more nigh it and then memorymanagement.org is an splendid resource, listing many publications and online manufactures. Further information almost object pooling tin exist found on the Wikipedia page and also at Sourcemaking.com.


  • 2020–06–02
  • Ability to disable garbage collection on Mono and IL2CPP scripting backends added in Unity 2018.3 NewIn20183
  • Added exerimental Incremental Garbage Drove feature added in Unity 2019.i NewIn20191
  • Added support for Incremental Garbage Collection on boosted platforms: PS4, XBox One, Nintendo Switch, and the Unity Editor. 2019.2 NewIn20192

Stable scripting runtime: known limitations

Referencing additional class library assemblies

jonesartimessill.blogspot.com

Source: https://docs.unity3d.com/2020.2/Documentation/Manual/UnderstandingAutomaticMemoryManagement.html

0 Response to "Unity Prevent Singleton Manager From Being Instantiated Again"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel