3D game freezing every 5 seconds, garbage collection

Hello, I’m currently developing a 3d multiplayer game in Monogame and noticing freezing every 5 seconds and quite allot of garbage collection. I’m trying to solve the issue by finding what creates garbage for the garbage collector and remove the garbage.

The games networking initializes variables in runtime as it collects data from the server, for example this code is checking what a player is wearing. This code is sent by the server when a player changes any gear it is wearing to update other players with the changes. (this code is called only in a specific situation)

But this code is always sent by the server unreliably so mostly every frame it will be initializing these variables.

Everything received from the server is setup to receive data in this way, I believe the initializing in runtime all these variables would be creating allot of memory for the garbage collector which may be causing the 1 second freezing every 5seconds.

The above code is drawing floating text on the screen, like damage being done to an enemy. Allot of the drawing would be handled like this and would be drawn every frame if there is damage being done to something. As you can see I would be initializing a string, vector2, float and color variable each draw frame multiplied by each damage number shown.

Another code being updated every draw frame, it checks if the player being drawn is within view distance of the camera and then within the view frustum of the camera. You can see it is initializing a double every draw frame.

and inside the draw function its initializing:
new SamplerState (for the shadow casting)

Matrix[] bones

Matrix getWorld (the players world transform into shader)
Matrix worldMatrix

float colorR (ambient sky color)
float colorG (ambient sky color)
float colorB (ambient sky color)

int MAXLIGHTS (total light sources in scene)
Vector3[] PointLightPosition = new Vector3[MAXLIGHTS];
Vector4[] PointLightColor = new Vector4[MAXLIGHTS];
float[] PointLightPower = new float[MAXLIGHTS];
float[] PointLightRadius = new float[MAXLIGHTS];

These would be initialized inside the draw call every draw frame if this player is within view distance of the player and view frustum of the camera.

I believe all these initialized variables in runtime every frame would be creating allot of garbage collection. Before I rework the whole game to eliminate calling new variables each frame I wanted to make sure this could be the reason for the garbage collection filling up and freezing the game every 5seconds. Thank you

Rather than sending and creating strings to send across have you thought about giving each item a unique int id, and an item type.

Then you can just send the int id of the item through (a lot less data) and on the receiving end look up the item type etc through the item id

Hello boot yes, your right it would be better to send an item’s id rather then its name as it would guarantee the id would be shorter then the name, I believe the reason its not like that is because the item database was originally sorted based as a dictionary<string, item>() and it used the items name to find a item the reason it wasn’t created as a list using a int as the id was because when you search for an item in your inventory for example using a dictionary is faster and easier to look up the item based on its name.

If I used a list with the int as the id I would have to search the whole list for the matching item before I can change or get any information about it.

Using an ID for items, you can still use a dictionary to look them up, just switch it to Dictionary<unsigned int, Item> instead. You could also use an enum if you wanted to.

Anyway, it seems odd to me that you’re getting a full second freeze every 5 seconds due to garbage collection. You might want to look into this. However, if you think your allocations are a performance bottleneck, you can just cache the storage for those if you want to. For example, in your first block of code…

if (messageTitle == "Equipment")
{
  string who = msg.ReadString();
  string helmet = msg.ReadString();
  ...
}

You can create a persistent object to handle this.

class EquipmentMessageProcessor
{
  private string _who;
  private string _helmet;
  ...

  public void ProcessMessage(string messageTitle, MessageType msg)
  {
    if (messageTitle == "Equipment")
    {
      _who = msg.ReadString();
      _helmet = msg.ReadString();
      ...
    }
  }
}

Stuff like that. As long as you keep the instance of EquipmentMessageProcessor around, you cut down on those allocations. Same goes for the rest of the areas. I wouldn’t worry about stuff like int and Vector2, but string could cause issues. I definitely wouldn’t initialize a new Stopwatch every frame though. That you can just have as a class member and call Reset each frame. You want to watch out for non-string non-primitive type allocations.

Still though, like I said this seems suspect. I’m curious, what has led you to believe that the freeze is due to garbage collection?

Before trying to solve the problem, you should definitely verify the source of the freeze. If it is truly memory allocation, you can verify this by using Visual Studio’s built-in tools:

That will tell you how much allocation you have, and also how often the garbage collector is running. You can see if the garbage collector running aligns with the freezes you are seeing.

If it is not GC, then it is likely something that is CPU bound, and for that you can also get information from Visual Studio.

Definitely use a dictionary with the item int id as the key. Thats an instant look up to find it, and you won’t have duplicate item types anyway

You can also shorten your transition bit rates by using codes rather than full strings for the information type to send and recieve information. Using Byte will give you 255 codes, and only takes 1 byte.

Also using an item id can also easy act as security

The server as well as the client has all these item with there id stored.

The server can act as a safeguard. Client tells the server, I’ve looted item #27 from monster #65 and put it in inventory slot 5. The server then verifys that this is possible then tells the client item 27 is now in slot 5.

Keep what you can server side. If the server has the main copy of all the information and it basically has to verify everything the client does, then it makes hacking and cheating harder.

Ideally if the client attacks a monster, the client says I’ve hit monster #10 with item #3. The server checks that your in range of monster #10, you have item #3 selected, calculates your damage, and sends back information monster #10 has lost 25 health

However this can cause latency delays. So you can also do damage calculation etc client side and send that to the server but then make the server verify that what you have done is legit, with a legitimate weapon etc. If the players done something illegal (has created a hack to move over obstacles( then roll the player back to its last legit position)

Just wanted to update everyone the freezing was actually not due to garbage collection, It was actually because of this line of code.

pingDelay += (float)gameTime.ElapsedGameTime.TotalSeconds;
if (pingDelay > 3)
{
ping = Int32.Parse(pingSender.Send(client.ServerConnection.RemoteEndPoint.Address, 120, Encoding.ASCII.GetBytes(“0”), options).RoundtripTime.ToString());
pingDelay = 0;
}

pingSender.Send() is supposed to be Async. Because it wasn’t it was freezing the game while it waited for the server to return the result.

Thankyou for your suggestion vchelaru, I tried profiling to see if I could pinpoint any issues with memory and I couldn’t find anything so I ended looking else where which is when I eventually noticed the code that was creating the problem.

Regarding the itemdatabase actually using the item ID as the ID in the dictionary, you are absolutely correct and I feel so silly using the name instead of the ID. Thankyou everyone for your help :slight_smile:

1 Like