Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Godot - Memory leakage in addon #57

Open
2shady4u opened this issue Oct 19, 2020 · 12 comments
Open

Godot - Memory leakage in addon #57

2shady4u opened this issue Oct 19, 2020 · 12 comments
Labels

Comments

@2shady4u
Copy link

2shady4u commented Oct 19, 2020

When adding the Nakama autoload singleton and running/exiting the game (without accessing any of Nakama's functionalities), the console reports memory leakage.

image

Steps to reproduce:

  • Make a new project and add a main scene
  • Enable "verbose stdout" in the Project Settings
  • Download "Nakama" from the Assetlib
  • Add the Nakama.gd as an autoload singleton
  • Run & Exit the main scene
  • Check the console for leaks!
@2shady4u
Copy link
Author

The full output:

Loading resource: res://addons/com.heroiclabs.nakama/client/NakamaClient.gd
Loading resource: res://addons/com.heroiclabs.nakama/api/NakamaStorageObjectId.gd
Loading resource: res://addons/com.heroiclabs.nakama/api/NakamaWriteStorageObject.gd
Loading resource: res://src/Menu.tscn
Loading resource: res://assets/materials/night_shader.tres
EditorSettings: Save OK!
ERROR: ~List: Condition "_first != __null" is true.
   At: ./core/self_list.h:112
ERROR: ~List: Condition "_first != __null" is true.
   At: ./core/self_list.h:112
WARNING: cleanup: ObjectDB instances leaked at exit (run with --verbose for details).
     At: core/object.cpp:2135
Leaked instance: GDScript:6840 - Resource path:
Leaked instance: GDScript:6813 - Resource path:
Leaked instance: GDScript:6820 - Resource path:
Leaked instance: GDScript:6854 - Resource path:
Leaked instance: GDScript:6836 - Resource path:
Leaked instance: GDScript:6850 - Resource path:
Leaked instance: GDScript:6816 - Resource path:
Leaked instance: GDScript:6817 - Resource path:
Leaked instance: GDScript:6865 - Resource path:
Leaked instance: GDScript:6861 - Resource path:
Leaked instance: GDScript:6830 - Resource path:
Leaked instance: GDScript:6860 - Resource path:
Leaked instance: GDScript:6814 - Resource path:
Leaked instance: GDScript:6829 - Resource path:
Leaked instance: GDScript:6859 - Resource path:
Leaked instance: GDScript:6855 - Resource path:
Leaked instance: GDScript:6811 - Resource path:
Leaked instance: GDScript:6810 - Resource path:
Leaked instance: GDScript:6807 - Resource path:
Leaked instance: GDScript:6834 - Resource path:
Leaked instance: GDScript:6852 - Resource path:
Leaked instance: GDScript:6839 - Resource path:
Leaked instance: GDScript:6853 - Resource path:
Leaked instance: GDScript:6863 - Resource path:
Leaked instance: GDScript:6835 - Resource path:
Leaked instance: GDScript:6867 - Resource path:
Leaked instance: GDScript:6791 - Resource path: res://addons/com.heroiclabs.nakama/utils/NakamaSerializer.gd
Leaked instance: GDScript:6819 - Resource path:
Leaked instance: GDScript:6848 - Resource path:
Leaked instance: GDScript:6847 - Resource path:
Leaked instance: GDScript:6812 - Resource path:
Leaked instance: GDScript:6846 - Resource path:
Leaked instance: GDScript:6845 - Resource path:
Leaked instance: GDScript:6809 - Resource path:
Leaked instance: GDScript:6869 - Resource path:
Leaked instance: GDScript:6808 - Resource path:
Leaked instance: GDScript:6827 - Resource path:
Leaked instance: GDScript:6868 - Resource path:
Leaked instance: GDScript:6785 - Resource path: res://addons/com.heroiclabs.nakama/utils/NakamaException.gd
Leaked instance: GDScript:6818 - Resource path:
Leaked instance: GDScript:6841 - Resource path:
Leaked instance: GDScript:6837 - Resource path:
Leaked instance: GDScript:6872 - Resource path:
Leaked instance: GDScript:6858 - Resource path:
Leaked instance: GDScript:6815 - Resource path:
Leaked instance: GDScript:6851 - Resource path:
Leaked instance: GDScript:6831 - Resource path:
Leaked instance: GDScript:6864 - Resource path:
Leaked instance: GDScript:6789 - Resource path: res://addons/com.heroiclabs.nakama/utils/NakamaAsyncResult.gd
Leaked instance: GDScript:6862 - Resource path:
Leaked instance: GDScript:6833 - Resource path:
Leaked instance: GDScript:6821 - Resource path:
Leaked instance: GDScript:6832 - Resource path:
Leaked instance: GDScript:6824 - Resource path:
Leaked instance: GDScript:6857 - Resource path:
Leaked instance: GDScript:6825 - Resource path:
Leaked instance: GDScript:6838 - Resource path:
Leaked instance: GDScript:6866 - Resource path:
Leaked instance: GDScript:6870 - Resource path:
Leaked instance: GDScript:6856 - Resource path:
Leaked instance: GDScript:6842 - Resource path:
Leaked instance: GDScript:6828 - Resource path:
Leaked instance: GDScript:6849 - Resource path:
Leaked instance: GDScript:6826 - Resource path:
Leaked instance: GDScript:6844 - Resource path:
Leaked instance: GDScript:6871 - Resource path:
Leaked instance: GDScript:6843 - Resource path:
Leaked instance: GDScriptNativeClass:553
Hint: Leaked instances typically happen when nodes are removed from the scene tree (with `remove_child()`) but not freed (with `free()` or `queue_free()`).
ERROR: clear: Resources still in use at exit (run with --verbose for details).
   At: core/resource.cpp:477
Resource still in use: res://addons/com.heroiclabs.nakama/utils/NakamaSerializer.gd (GDScript)
Resource still in use: res://addons/com.heroiclabs.nakama/utils/NakamaAsyncResult.gd (GDScript)
Resource still in use: res://addons/com.heroiclabs.nakama/utils/NakamaException.gd (GDScript)
Orphan StringName: vars
Orphan StringName: _get_permission_read
Orphan StringName: _duration
Orphan StringName: duration
Orphan StringName: deserialize
Orphan StringName: ApiTournamentRecordList
Orphan StringName: online
Orphan StringName: _get_objects
Orphan StringName: edge_count
Orphan StringName: _tournaments
Orphan StringName: ApiMatchList
Orphan StringName: _get_max_count
Orphan StringName: p_type
Orphan StringName: GroupUserListGroupUser
Orphan StringName: ApiUser
Orphan StringName: _get_group
Orphan StringName: message_id
Orphan StringName: ApiAccountSteam
Orphan StringName: ApiAccountFacebook
Orphan StringName: permission_read
Orphan StringName: _get_permission_write
Orphan StringName: _get_edge_count
Orphan StringName: _timestamp_seconds
Orphan StringName: joins
Orphan StringName: object_ids
Orphan StringName: _get_value
Orphan StringName: escape_http
Orphan StringName: _get_message_id
Orphan StringName: Channel
Orphan StringName: _get_num_score
Orphan StringName: data
Orphan StringName: _get_category
Orphan StringName: ApiEvent
Orphan StringName: exception
Orphan StringName: _get_open
Orphan StringName: _get_object_ids
Orphan StringName: creator_id
Orphan StringName: _lang_tag
Orphan StringName: lang_tag
Orphan StringName: _end_time
Orphan StringName: MatchPresenceEvent
Orphan StringName: end_time
Orphan StringName: _get_public_key_url
Orphan StringName: _get_online
Orphan StringName: ApiWriteStorageObject
Orphan StringName: owner_records
Orphan StringName: res://addons/com.heroiclabs.nakama/utils/NakamaSerializer.gd
Orphan StringName: sort_order
Orphan StringName: _get_creator_id
Orphan StringName: numeric_properties
Orphan StringName: timestamp_seconds
Orphan StringName: user_id
Orphan StringName: subcontext
Orphan StringName: _get_location
Orphan StringName: public_key_url
Orphan StringName: _user_groups
Orphan StringName: _get_external
Orphan StringName: devices
Orphan StringName: _subject
Orphan StringName: WriteTournamentRecordRequestTournamentRecordWrite
Orphan StringName: ApiUserGroupList
Orphan StringName: wallet
Orphan StringName: op_code
Orphan StringName: _start_time
Orphan StringName: ApiSession
Orphan StringName: _state
Orphan StringName: _get_sort_order
Orphan StringName: _channel_id
Orphan StringName: max_num_score
Orphan StringName: _title
Orphan StringName: verify_time
Orphan StringName: _salt
Orphan StringName: _get_metadata
Orphan StringName: create
Orphan StringName: _get_verify_time
Orphan StringName: StreamPresenceEvent
Orphan StringName: get_exception
Orphan StringName: score
Orphan StringName: _create_time
Orphan StringName: _user_id_two
Orphan StringName: get_result_key
Orphan StringName: Reference
Orphan StringName: ApiAccountGameCenter
Orphan StringName: ApiAccountEmail
Orphan StringName: persistence
Orphan StringName: start_active
Orphan StringName: _player_id
Orphan StringName: MatchmakerTicket
Orphan StringName: _get_steam_id
Orphan StringName: _email
Orphan StringName: self_user
Orphan StringName: _get_user_id
Orphan StringName: _to_string
Orphan StringName: player_id
Orphan StringName: _room_name
Orphan StringName: _get_devices
Orphan StringName: serialize
Orphan StringName: p_val
Orphan StringName: room_name
Orphan StringName: _get_google_id
Orphan StringName: _get_signature
Orphan StringName: _get_owner_id
Orphan StringName: _next_reset
Orphan StringName: acks
Orphan StringName: _custom_id
Orphan StringName: ChannelMessageAck
Orphan StringName: _get_state
Orphan StringName: _get_wallet
Orphan StringName: custom_id
Orphan StringName: _get_title
Orphan StringName: _get_http_key
Orphan StringName: _gamecenter_id
Orphan StringName: _get_salt
Orphan StringName: new
Orphan StringName: _facebook_instant_game_id
Orphan StringName: _online
Orphan StringName: _get_gamecenter_id
Orphan StringName: _ex
Orphan StringName: GDScriptNativeClass
Orphan StringName: _get_cacheable_cursor
Orphan StringName: duplicate
Orphan StringName: _max_size
Orphan StringName: max_size
Orphan StringName: _get_email
Orphan StringName: _sender_id
Orphan StringName: _get_group_id
Orphan StringName: _name
Orphan StringName: ApiUsers
Orphan StringName: sender_id
Orphan StringName: p_dict
Orphan StringName: ApiAccount
Orphan StringName: _id
Orphan StringName: display_name
Orphan StringName: _get_bundle_id
Orphan StringName: _get_password
Orphan StringName: ApiStorageObjectAck
Orphan StringName: ApiStorageObjects
Orphan StringName: _collection
Orphan StringName: _public_key_url
Orphan StringName: res://addons/com.heroiclabs.nakama/utils/NakamaException.gd
Orphan StringName: ApiReadStorageObjectId
Orphan StringName: _get_messages
Orphan StringName: _content
Orphan StringName: groups
Orphan StringName: _token
Orphan StringName: label
Orphan StringName: _safe_ret
Orphan StringName: expiry_time
Orphan StringName: StatusPresenceEvent
Orphan StringName: MatchmakerUser
Orphan StringName: p_obj
Orphan StringName: _payload
Orphan StringName: _get_expiry_time
Orphan StringName: authoritative
Orphan StringName: subject
Orphan StringName: v
Orphan StringName: _verify_time
Orphan StringName: _get_can_enter
Orphan StringName: _get_username
Orphan StringName: _get_name
Orphan StringName: UserGroupListUserGroup
Orphan StringName: _created
Orphan StringName: _notifications
Orphan StringName: _size
Orphan StringName: p_exception
Orphan StringName: facebook_instant_game_id
Orphan StringName: _rank
Orphan StringName: p_status_code
Orphan StringName: p_cls_name
Orphan StringName: MatchmakerMatched
Orphan StringName: get
Orphan StringName: required
Orphan StringName: _wallet
Orphan StringName: _friends
Orphan StringName: start_time
Orphan StringName: channel_id
Orphan StringName: _get_notifications
Orphan StringName: ApiAccountCustom
Orphan StringName: _get_timestamp
Orphan StringName: ApiNotificationList
Orphan StringName: _properties
Orphan StringName: group
Orphan StringName: _p
Orphan StringName: _avatar_url
Orphan StringName: _code
Orphan StringName: _user
Orphan StringName: _get_token
Orphan StringName: _get_start_time
Orphan StringName: _get_groups
Orphan StringName: _get_channel_id
Orphan StringName: presence
Orphan StringName: value
Orphan StringName: _get_subject
Orphan StringName: ApiStorageObject
Orphan StringName: open
Orphan StringName: UserPresence
Orphan StringName: group_users
Orphan StringName: description
Orphan StringName: key
Orphan StringName: ApiChannelMessage
Orphan StringName: ApiTournament
Orphan StringName: _max_count
Orphan StringName: ApiDeleteStorageObjectsRequest
Orphan StringName: _get_group_users
Orphan StringName: leaves
Orphan StringName: _get_description
Orphan StringName: max_count
Orphan StringName: _users
Orphan StringName: _get_size
Orphan StringName: next_reset
Orphan StringName: _get_rank
Orphan StringName: ChannelPresenceEvent
Orphan StringName: _end_active
Orphan StringName: id
Orphan StringName: _get_match_id
Orphan StringName: _category
Orphan StringName: category
Orphan StringName: _get_next_reset
Orphan StringName: ApiTournamentList
Orphan StringName: _version
Orphan StringName: _num_score
Orphan StringName: _get_code
Orphan StringName: _vars
Orphan StringName: _get_user
Orphan StringName: self_presence
Orphan StringName: sender
Orphan StringName: _matches
Orphan StringName: _get_timezone
Orphan StringName: num_score
Orphan StringName: _get_subscore
Orphan StringName: grpc_status_code
Orphan StringName: _get_timestamp_seconds
Orphan StringName: ticket
Orphan StringName: user_id_one
Orphan StringName: _permission_write
Orphan StringName: ApiChannelMessageList
Orphan StringName: append
Orphan StringName: _get_leaderboard_id
Orphan StringName: ApiLeaderboardRecordList
Orphan StringName: _get_duration
Orphan StringName: MatchData
Orphan StringName: _get_user_id_one
Orphan StringName: _location
Orphan StringName: location
Orphan StringName: _owner_records
Orphan StringName: cursor
Orphan StringName: ApiNotification
Orphan StringName: _external
Orphan StringName: external
Orphan StringName: Status
Orphan StringName: p_str
Orphan StringName: Stream
Orphan StringName: _get_users
Orphan StringName: _records
Orphan StringName: _expiry_time
Orphan StringName: leaderboard_id
Orphan StringName: base64_to_utf8
Orphan StringName: _get_owner_records
Orphan StringName: content
Orphan StringName: string_properties
Orphan StringName: collection
Orphan StringName: set
Orphan StringName: ApiReadStorageObjectsRequest
Orphan StringName: _metadata
Orphan StringName: metadata
Orphan StringName: _signed_player_info
Orphan StringName: status_code
Orphan StringName: _get_key
Orphan StringName: payload
Orphan StringName: _max_num_score
Orphan StringName: ApiUpdateGroupRequest
Orphan StringName: permission_write
Orphan StringName: _groups
Orphan StringName: _persistent
Orphan StringName: _SCHEMA
Orphan StringName: _get_vars
Orphan StringName: state
Orphan StringName: _get_collection
Orphan StringName: salt
Orphan StringName: prev_cursor
Orphan StringName: title
Orphan StringName: _get_max_num_score
Orphan StringName: created
Orphan StringName: next_cursor
Orphan StringName: _steam_id
Orphan StringName: mode
Orphan StringName: steam_id
Orphan StringName: Match
Orphan StringName: _get_prev_cursor
Orphan StringName: friends
Orphan StringName: _get_next_cursor
Orphan StringName: _get_lang_tag
Orphan StringName: _get_end_time
Orphan StringName: update_time
Orphan StringName: _owner_id
Orphan StringName: owner_id
Orphan StringName: _get_cursor
Orphan StringName: _google_id
Orphan StringName: _start_active
Orphan StringName: _get_id
Orphan StringName: _signature
Orphan StringName: p_grpc_status_code
Orphan StringName: _get_content
Orphan StringName: res://addons/com.heroiclabs.nakama/api/NakamaRTAPI.gd
Orphan StringName: google_id
Orphan StringName: _get_update_time
Orphan StringName: signature
Orphan StringName: Object
Orphan StringName: _http_key
Orphan StringName: http_key
Orphan StringName: email
Orphan StringName: _get_payload
Orphan StringName: _objects
Orphan StringName: _group_users
Orphan StringName: _description
Orphan StringName: _get_start_active
Orphan StringName: properties
Orphan StringName: avatar_url
Orphan StringName: ApiUpdateAccountRequest
Orphan StringName: _score
Orphan StringName: _get_facebook_instant_game_id
Orphan StringName: _get_created
Orphan StringName: p_ex
Orphan StringName: facebook_id
Orphan StringName: _get_friends
Orphan StringName: _get_properties
Orphan StringName: _get_avatar_url
Orphan StringName: _group_id
Orphan StringName: group_id
Orphan StringName: _permission_read
Orphan StringName: _get_facebook_id
Orphan StringName: p_message
Orphan StringName: _get_player_id
Orphan StringName: ApiAccountDevice
Orphan StringName: _edge_count
Orphan StringName: _acks
Orphan StringName: _key
Orphan StringName: _password
Orphan StringName: password
Orphan StringName: _get_room_name
Orphan StringName: name
Orphan StringName: _bundle_id
Orphan StringName: version
Orphan StringName: ApiGroup
Orphan StringName: ApiWriteStorageObjectsRequest
Orphan StringName: end_active
Orphan StringName: matches
Orphan StringName: bundle_id
Orphan StringName: _user_id_one
Orphan StringName: _message_id
Orphan StringName: _cacheable_cursor
Orphan StringName: _get_custom_id
Orphan StringName: _display_name
Orphan StringName: _messages
Orphan StringName: messages
Orphan StringName: _get_score
Orphan StringName: _leaderboard_id
Orphan StringName: gamecenter_id
Orphan StringName: WriteLeaderboardRecordRequestLeaderboardRecordWrite
Orphan StringName: ApiLeaderboardRecord
Orphan StringName: p_ns
Orphan StringName: _object_ids
Orphan StringName: tournaments
Orphan StringName: _no_set
Orphan StringName: _get_end_active
Orphan StringName: ApiAccountFacebookInstantGame
Orphan StringName: ApiStorageObjectAcks
Orphan StringName: _get_tournaments
Orphan StringName: type
Orphan StringName: ApiGroupList
Orphan StringName: ApiAccountGoogle
Orphan StringName: records
Orphan StringName: _get_display_name
Orphan StringName: ApiFriendList
Orphan StringName: _creator_id
Orphan StringName: _username
Orphan StringName: username
Orphan StringName: token
Orphan StringName: status
Orphan StringName: stream
Orphan StringName: _can_enter
Orphan StringName: _cursor
Orphan StringName: ApiGroupUserList
Orphan StringName: ApiCreateGroupRequest
Orphan StringName: _authoritative
Orphan StringName: can_enter
Orphan StringName: _get_signed_player_info
Orphan StringName: ApiRpc
Orphan StringName: _get_version
Orphan StringName: cacheable_cursor
Orphan StringName: to_hex
Orphan StringName: _get_sender_id
Orphan StringName: _get_max_size
Orphan StringName: _get_acks
Orphan StringName: _sort_order
Orphan StringName: _get_matches
Orphan StringName: to_utf8
Orphan StringName: _init
Orphan StringName: _prev_cursor
Orphan StringName: _get_authoritative
Orphan StringName: _next_cursor
Orphan StringName: size
Orphan StringName: rank
Orphan StringName: _timestamp
Orphan StringName: _label
Orphan StringName: timestamp
Orphan StringName: _user_id
Orphan StringName: _update_time
Orphan StringName: persistent
Orphan StringName: _devices
Orphan StringName: _get_records
Orphan StringName: HEX
Orphan StringName: ApiDeleteStorageObjectId
Orphan StringName: code
Orphan StringName: user_groups
Orphan StringName: user
Orphan StringName: GDScript
Orphan StringName: _get_persistent
Orphan StringName: _get_user_groups
Orphan StringName: message
Orphan StringName: presences
Orphan StringName: objects
Orphan StringName: signed_player_info
Orphan StringName: ApiFriend
Orphan StringName: notifications
Orphan StringName: reliable
Orphan StringName: _match_id
Orphan StringName: match_id
Orphan StringName: create_time
Orphan StringName: user_id_two
Orphan StringName: _facebook_id
Orphan StringName: _group
Orphan StringName: res://addons/com.heroiclabs.nakama/api/NakamaAPI.gd
Orphan StringName: _get_label
Orphan StringName: StreamData
Orphan StringName: users
Orphan StringName: _get_create_time
Orphan StringName: _get_user_id_two
Orphan StringName: _timezone
Orphan StringName: is_exception
Orphan StringName: timezone
Orphan StringName: _value
Orphan StringName: ApiStorageObjectList
Orphan StringName: _subscore
Orphan StringName: subscore
Orphan StringName: ApiMatch
Orphan StringName: session_id
Orphan StringName: _open
Orphan StringName: res://addons/com.heroiclabs.nakama/utils/NakamaAsyncResult.gd
StringName: 449 unclaimed string names at exit.

@Faless
Copy link
Contributor

Faless commented Nov 16, 2020

This is probably an upstream bug with global scripts.

@n3rdw1z4rd
Copy link

Any movement on fixing the memory leaks?

@novabyte
Copy link
Member

@JohnCWakley I think at the time we determined it was a misrepresentation in the leak detection in the Godot engine. It's been a while since we looked at it. Have you seen a similar report of output with global scripts in the latest Godot engine?

@n3rdw1z4rd
Copy link

@novabyte Yes, in Godot v3.3.2.stable.official, I am seeing the memory leaks for Reference inherited classes from Nakama:

...
Leaked instance: GDScript:1207 - Resource path: res://addons/com.heroiclabs.nakama/utils/NakamaException.gd
Leaked instance: GDScript:1213 - Resource path: res://addons/com.heroiclabs.nakama/utils/NakamaSerializer.gd
Leaked instance: GDScript:1211 - Resource path: res://addons/com.heroiclabs.nakama/utils/NakamaAsyncResult.gd
...
Hint: Leaked instances typically happen when nodes are removed from the scene tree (with `remove_child()`) but not freed (with `free()` or `queue_free()`).
ERROR: clear: Resources still in use at exit (run with --verbose for details).
   At: core/resource.cpp:450
Resource still in use: res://addons/com.heroiclabs.nakama/utils/NakamaSerializer.gd (GDScript)
Resource still in use: res://addons/com.heroiclabs.nakama/utils/NakamaAsyncResult.gd (GDScript)
Resource still in use: res://addons/com.heroiclabs.nakama/utils/NakamaException.gd (GDScript)
...
Orphan StringName: res://addons/com.heroiclabs.nakama/utils/NakamaAsyncResult.gd
StringName: 449 unclaimed string names at exit.

I have contributed code to the Godot project, when I get some time, I will investigate the leak detection and see if there are any potential issues to fix...

@dsnopek
Copy link
Contributor

dsnopek commented Mar 2, 2022

I just re-tested the steps to reproduce using Godot 3.4.3, both with the version currently in the asset library as well as the current 'master' branch, and, unfortunately, I'm still seeing the output about leaked instances and orphaned string names.

@dsnopek dsnopek added this to To do in nakama-godot Mar 16, 2022
@lugehorsam lugehorsam changed the title Memory leakage in addon Godot - Memory leakage in addon Sep 21, 2022
@Carbone13
Copy link

any news on this ?

@WolfgangSenff
Copy link

I'm not completely certain of this, but it looks like the common issue in Godot - the one @novabyte mentioned. In my experience, generally speaking , this can be ignored - it will happen most times you have an autoload, due to timing when the autoloads are unloaded and when the game officially "shuts down" (since autoloads are static, they must remain in memory for the duration of the app run, at least in my head!).

@dsnopek
Copy link
Contributor

dsnopek commented Nov 2, 2022

Yeah, the last time someone investigated this in-depth, it was concluded to be a "false positive", ie Godot's memory leak detection incorrectly flagging these as memory leaks. It'd be great to dig into it again and somehow prevent that, but it's not a high priority

@puzzud
Copy link

puzzud commented Feb 28, 2024

Some additional observations I've made:

  • This still occurs if Nakama.gd is set as a disabled autoload script.
  • Does not occur if removed from autoload script list entirely.
  • Still happens if attaching Nakama.gd to a node within a scene's tree.

Even if I queue_free that node almost immediately upon startup, the memory leak related messages still occurs around program termination, suggesting this issue does not depend on Godot's autoload mechanism.

Searching around raises my suspicion that this might have something to do with type dependency resolution.

@puzzud
Copy link

puzzud commented Feb 29, 2024

After a bit of surgery, I have determined the immediate cause of this error.

The assorted internal classes defined in NakamaAPI.gd and NakamaRTAPI.gd which extend NakamaAsyncResult feature a static method called create which is static typed to return an object matching its class--a factory method.

Here is an example:

static func create(p_ns : GDScript, p_dict : Dictionary) -> Channel:
	return _safe_ret(NakamaSerializer.deserialize(p_ns, "Channel", p_dict), Channel) as Channel

From my experience, I was surprised that this code did not fail parsing, as in Godot 3, classes cannot self class reference. Interestingly enough, just removing the as Channel is enough to avoid this issue--I was shocked it does not have an issue with -> Channel.

Going through both files and stripping the "as" casting resolves this issue.

I tested Godot 3.6-beta4 and the problem still exists.

I tested Godot 4.2-stable and the problem does not exist. Additionally, all forms of self class referencing that I could think of were all possible.

Because cyclical class references are supported in Godot 4 but more or less intentionally not in Godot 3, this issue is technically not a Godot bug. If it were to be addressed in Godot 3, I would suspect it would simply fail parsing, just as this code does:

if foo is Channel:
	pass

And an alternate Nakama implementation would be required, such as the adjustment I mentioned or perhaps the use of separate factory classes over static methods.

I'll draft up a pull request to target the Godot 3 branch.

@novabyte
Copy link
Member

Thank you for the detailed debugging @puzzud it would be great to have a pull request to review 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
No open projects
Development

No branches or pull requests

9 participants