godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
89.22k stars 20.23k forks source link

[3.4] Memory leak? between Dictionary(godot) and Dictionary(C#) #55027

Closed git2013vb closed 2 years ago

git2013vb commented 2 years ago

Godot version

v3.4.stable.mono.official [206ba70f4]

System information

Debian 11

Issue description

This code give the issue:

  public System.Collections.Generic.Dictionary<int, Dictionary> SystemDict =
             new System.Collections.Generic.Dictionary<int, Dictionary>();
        public override void _PhysicsProcess(float delta)
        {
            Dictionary GodotDict = new Dictionary() { ["A"] = "1" };
            SystemDict[1] = GodotDict;
            GD.Print(SystemDict);
            GD.Print(GodotDict);
        }

Steps to reproduce

Run it and check in Debugger TAB -> Monitors (Static + Static Max)

Minimal reproduction project

TestDictionary.zip

kleonc commented 2 years ago

No leak in here, it's just GC not kicking in.

You can find many similar issues by searching for "leak" and topic:mono, e.g. #46497, #41543.

git2013vb commented 2 years ago

Right... The problem is: I have no idea how to make a workaround - if exist. I use Dictionary(godot) to move data between server-clients(rpc 60 fps) and use Dictionary(c#) in order be able to use linq... So I'm stuck again I guess :) edit: @Calinou My mistake. There is not involved any C# Dictionary

I think is a bug nevertheless. Here a real case scenario:

LOG: From timestamp you can see the rate I use.

(1115089) 10:49:12.144  :DEBUG  GameServer 121 Void ReceivePlayerState(Godot.Collections.Dictionary){P:(834, 8890), R:1.425647, S:(1, 1), T:1637142546066}  <--->  {1342181811:{P:(834, 8890), R:1.425647, S:(1, 1), T:1637142546066}} 
(1115089) 10:49:12.162  :DEBUG  GameServer 121 Void ReceivePlayerState(Godot.Collections.Dictionary){P:(834, 8890), R:1.425647, S:(1, 1), T:1637142546082}  <--->  {1342181811:{P:(834, 8890), R:1.425647, S:(1, 1), T:1637142546082}} 
(1115089) 10:49:12.179  :DEBUG  GameServer 121 Void ReceivePlayerState(Godot.Collections.Dictionary){P:(834, 8890), R:1.425647, S:(1, 1), T:1637142546098}  <--->  {1342181811:{P:(834, 8890), R:1.425647, S:(1, 1), T:1637142546098}} 
(1115089) 10:49:12.213  :DEBUG  GameServer 121 Void ReceivePlayerState(Godot.Collections.Dictionary){P:(834, 8890), R:1.425647, S:(1, 1), T:1637142546114}  <--->  {1342181811:{P:(834, 8890), R:1.425647, S:(1, 1), T:1637142546114}} 
(1115089) 10:49:12.213  :DEBUG  GameServer 121 Void ReceivePlayerState(Godot.Collections.Dictionary){P:(834, 8890), R:1.425647, S:(1, 1), T:1637142546130}  <--->  {1342181811:{P:(834, 8890), R:1.425647, S:(1, 1), T:1637142546130}} 
(1115089) 10:49:12.229  :DEBUG  GameServer 121 Void ReceivePlayerState(Godot.Collections.Dictionary){P:(834, 8890), R:1.425647, S:(1, 1), T:1637142546146}  <--->  {1342181811:{P:(834, 8890), R:1.425647, S:(1, 1), T:1637142546146}} 
(1115089) 10:49:12.263  :DEBUG  GameServer 121 Void ReceivePlayerState(Godot.Collections.Dictionary){P:(834, 8890), R:1.425647, S:(1, 1), T:1637142546162}  <--->  {1342181811:{P:(834, 8890), R:1.425647, S:(1, 1), T:1637142546162}} 
(1115089) 10:49:12.263  :DEBUG  GameServer 121 Void ReceivePlayerState(Godot.Collections.Dictionary){P:(834, 8890), R:1.425647, S:(1, 1), T:1637142546178}  <--->  {1342181811:{P:(834, 8890), R:1.425647, S:(1, 1), T:1637142546178}} 
(1115089) 10:49:12.282  :DEBUG  GameServer 121 Void ReceivePlayerState(Godot.Collections.Dictionary){P:(834, 8890), R:1.425647, S:(1, 1), T:1637142546194}  <--->  {1342181811:{P:(834, 8890), R:1.425647, S:(1, 1), T:1637142546194}} 

CODE: ps.: ALL Dictionary are Godot.

public static Dictionary<int, Dictionary> playerStateCollection = new Dictionary<int, Dictionary>();
     [Remote]
        public void ReceivePlayerState(Dictionary transform)
        {
            int playerID = GetTree().GetRpcSenderId();
            int result = playerStateCollection.Count(p => p.Key == playerID);
            if (result > 0)
            {
                if (Convert.ToUInt64(playerStateCollection.First(p => p.Key == playerID).Value["T"]) < Convert.ToUInt64(transform["T"]))
                {
                    playerStateCollection[playerID] = transform;
                }
            }
            else
            {
                playerStateCollection[playerID] = transform;
            }
            Log.Print(Log.DEBUG, Log.WHITE_BOLD, transform, "  <--->  ", playerStateCollection);
        }

here the screen shot from editor: If I'm right GC is active and it work. But its not able to clean everything.

DeepinScreenshot_select-area_20211117104906

Seems happen when a Dictionary nested structure is involved

git2013vb commented 2 years ago

I investigate a bit more and seems its not Dictionary fault, But I'm not sure 100%.

From this minimum project GC work fine- I used Godot Dictionary - . It seems.

In my original projet are involved more things lke linq, rpc..

It is possible to set something to be able to isolate the problem?

TestDictionary.zip

edit: I opened an tread in forum https://godotforums.org/discussion/28054/how-to-debug-a-specified-case-memory-leak#latest

kleonc commented 2 years ago

TestDictionary.zip

In this one I don't see any leak too. So I still don't see the issue.

git2013vb commented 2 years ago

TestDictionary.zip

In this one I don't see any leak too. So I still don't see the issue.

Exactly. My point was :Dictionary not leak. If you re read my post you can see what I said :) My tests show me that is the rpc call who leak (as mentioned in #55086)

kleonc commented 2 years ago

Exactly. My point was :Dictionary not leak.

So because:

I think there's nothing more to do in this issue and it can be closed.

git2013vb commented 2 years ago

Agree :)