Can Garbage Collector language be used for games?

Asked

Viewed 478 times

23

I started learning C# and even Java for interest in game development. But I know that many are developed with C++, mainly because I don’t have one Garbage Collector. Of course I know that several games are made in C# and Java.

I imagine it’s the pause that causes trouble. What I really want to know is how is resolved the pause in the development of a game made in these languages.

  • 2

    I’m also interested in games and those languages - I don’t understand why "pause" would cause any problems - what pause are you talking about?

  • 1

    @Danielgomes you appear on the set in a machine, sends to another information, the other player will see you to shoot, but before showing starts a collection, the game is delayed because of this, then appears, he takes a shot, only in your machine did not pause, you are no longer there. Should you take the shot? It gets weird. If you should not the other player failed to kill you because the software did not leave and not because of his inability.

  • The Go language has devoted much effort to lessening the pause caused by the garbage collector so as not to be a problem.

3 answers

21


Any language that uses a garbage collector in systems real team will have problems because the memory release time is not deterministic, which is a fundamental feature for real-time system. Even in manual memory is a problem when there is cascade or the allocation or release algorithm is efficient in memory saving and may have difficulty dealing with the free list memory. When using dynamic memory the real team really it is not possible.

Semi applications real team are already easier because no one will die if there is a slight delay. This is the case of games. The frames need to be updated in controlled time and there cannot be too long an operation that makes you miss the correct update time.

A naive GC certainly brings serious problems to games, but not a generational one, which is the case of C# or Java.

The collection of Gen0 is very fast, in general computo is usually faster than manual memory management in heap, outside the gain that can be obtained by the reference location.

The Gen1 is not so good, but it is short and with maximum time more or less defined. Since this time is considered it is possible to maintain a reliability.

The Gen2 is the problem, but is well minimized since it is done in background with normal application execution. On machines over 1 core the break may be as short as in previous generations.

You should know that several games are made in C#, mainly with Unity. And they have enough success in memory management.

Unfortunately C# can notand(ia) set up a lot of things in GC and you cannot change GC easily as Java allows, although the most appropriate alternatives to real team are usually quite expensive ($). The .NET Core does not give as much ease, but can exchange for another garbage collector or change small details. Mono also allows you to configure and change the GC. Other implementations like Xbox, Compact, and Micro Framework may have deterministic GC (I don’t know how it is today), but it probably won’t use the latter for games. In fact now only survived the . NET Core.

Optimization techniques

Most of what I’m about to say is true of any language (C or C++ for example may be faster, more controlled, but nobody says it’s a monster job), one with Garbage Collector only needs more care. At some points the languages with managed memory are even better.

  • Avoid using the heap as much as possible, so it doesn’t have the cost of collecting or releasing. C# has more and more resources to prefer the stack.
  • Understand how each component works and know where allocations occur, especially those that are usually invisible to the programmer as Boxing. You can only avoid allocations if you know they exist (example of how to avoid).
  • If you use the heap seek to make pre-allocations that will never be released, use the so-called Object Pool (see the great explanation of Luiz Vieira) or Flyweight Pattern. It has structures that already function as pools if you want, an example is List where you can clean instead of delete, so keep the allocation already made for a new use of the list. If delete, generates a trash and then generates another object for this new list.
  • Make the code less object oriented that abuse references.
  • Never forget that objects must die young or live forever.
  • In some cases you will need to build your own data structures or use third-party libraries that are best suited to the need. The new C# compiler has a lot of structure that looks like duplication of what already exists in the . NET, but they were written for the need of the compiler.
  • In extreme case aloque out of managed memory. Then it happens to be your problem to manage, but it is a way to have control when the release will take place. Just be careful not to leak memory. C#, unlike Java allows you to manage memory when there is no other better solution.
  • Use TryStartNoGCRegion() whenever there is a moment that can not have a collection, is not guaranteeing, but helps.
  • Knowing how to do, call the collection manually when it’s between levels, pause or something that doesn’t get in the way of a pause, it can minimize the chance of pause during the game’s action. But if you do wrong, it could make things worse.
  • Don’t forget to keep configured to use Workstation mode that slows down pauses.
  • Profile the application to find out where the problem is.
  • Specify a good minimum amount of memory. GC works best when it has spare memory.
  • Make the threads help in the organization of the software (something much more advanced).
  • It has techniques to keep the game late to avoid surprises, but this is not simple to do correctly and does not always solve.

Behold How to identify and avoid memory Leak on . NET?.

In short, produce less waste and make the GC work in your favor.

  • thank you very much for the answer (even if I am not asking). But can you tell me what the loaded objects look like in a scene in Unity, after this scene is over? For example: When entering a scene where is the "football field". When the game is over, and you return to the menu, would you tell me if the memory allocated by the "football field" is fully released? I know that here in this comment I was a little out of context, but I’ve been looking over and I didn’t find things very satisfying to read.

  • @Arturotemplário About Unity I know almost nothing.

  • @Arturotemplário, I have never made such a big game, so I know little... In Unity, it only loads the objects in the scene when you have the scene loaded; so that means it will avoid creating the football before you have it done. On abandoning existing scenes (after departure, for example), you need to talk to Unity to do this SceneManager.UnloadSceneAsync. Assets need to be released separately: Resources.UnloadAllUnusedAssets. More details on Scenemanager

18

I started learning C# and even Java for interest in developing games. But I know that many are developed with C++, mainly for not having a Garbage Collector.

This is not necessarily true. Many games are (or were) developed in C++ primarily for portability and performance reasons. But this reality has changed considerably with game engines like Unity3d. Today it is more common to develop the game almost entirely in one of these tools, and use C++ only for critical code (for example, some special crash test that needs to be done, or some calculation of Artificial Intelligence). As already explained to you in other answers, even a language in which you do not have GC vc may have problems if you plan incorrectly the use of memory.

Of course I know that several games are made in C# and Java.

Precisely because of the productivity obtained with tools and/or libraries that use these languages. But I still doubt that the main motivator of use is the existence or not of GC.

I imagine it’s the pause that causes trouble. What I really want to know is how is resolved the pause in the development of a game made in these languages.

I don’t understand what pause you are referring to. Is it the game break, or the interval that GC takes to remove the no longer referenced memory? If you were referring to the first, there is no reason for this to be a problem because during this time no object is created or deleted (supposedly, of course - after all, you may have made mistakes in your pause implementation). If you were referring to the second (which I think most likely), the accepted answer explains everything to you in technical detail but the essence is in: "produce less waste and make the GC work in your favor".

In a game, "produce garbage" is to create objects (i.e., allocate memory) and then throw them away (i.e., fail to reference that memory). It’s a very easy thing to do. For example, imagine a simple game where you shoot planes with an anti-aircraft battery from the ground. The game will constantly instantiate:

  1. Aeroplanes
  2. Projectiles launched by anti-aircraft battery

Planes and shells are both destroyed when the first is hit by the second, right? In addition, the aircraft will eventually leave the screen if they are not hit, just as the projectiles will exit the screen if they do not hit a target. If you instantiate new objects from these classes and destroy them when an impact occurs or when they leave the screen, you you won’t have memory leaks (i.e., memory eternally trapped and unusable), and your game will work super well. For simple games where few of these objects are instantiated, you don’t have to worry and can let the GC do its work the way it was designed.

But what if your game is complex enough for you to have many of these objects? In this case, it may not make sense to create and destroy objects continuously, as the load on the GC will be very large and constant (that is, you will be producing a lot of garbage and not making the GC work in your favor). An alternative in such cases is to use "tanks" (pools in English) of pre-created objects that are relocated after use (for example, the same bullet that exits the screen is made invisible and "transported" again to the mouth of the cannon to be fired again).

Leaving pre-created objects helps in performance because it doesn’t overload the GC, but of course memory has its limits and you can’t just let this "tank" grow indefinitely. So relocating objects is usually a good practice.

Finally, this has to be done carefully, considering not only the technical aspects discussed here, but also the player’s experience (which is something very important in this type of software). A classic example is the bullet holes left on the walls of Counterstrike. They are probably objects held in one of these types of "tanks" and are relocated when the "tank" runs out. It works well, but has already caused immersion breakage in players who have literally tried to write on walls with shots (the initial letters faded as the bullet hole objects were relocated). :)

  • 2

    Very good explanation of Object pool which is useful also when opting for management by malloc/free-like.

11

Specifically for Java, there are two items I would highlight on the subject:

First, the Java GC is not a mystery. In fact, there are more than one and each with different configurations that can meet specific demands, as some tend to have shorter and frequent breaks while other lengthy and rare breaks. In addition to small techniques and patterns that avoid the creation and subsequent unnecessary disposal of objects, if you develop a serious game, you will analyze the memory needed in each part of the game, monitor pauses, and simply try to allocate enough memory to the JVM so that it is not necessary to pause the execution at an inappropriate time, possibly by invoking the GC between stages or stages of the game.

Second, there are more advanced optimizations using directly allocated memory. See the documentation of ByteBuffer. In addition, much of the visual components can also be managed via integration with native drivers, such as memory of graphics cards, which are not managed by GC.

Anyway, I’m not arguing that Java is a suitable language for games, let alone large games, because GC is only one factor. However, if you know what you’re doing - and certainly a serious game will need an expert on the platform used - GC breaks probably won’t be your biggest concern.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.