Browse Source

Fixed leak on exit when using yield with SceneTreeTimer

Use case:
yield(get_tree().create_timer(2), "timeout")

Some resources were never released because the SceneTreeTimer was keeping a reference to GDScriptFunctionState in its signal connections, while GDScriptFunctionState was holding a reference to the SceneTreeTimer object. Cleaning all signal connections on game exit fixes the issue.

Fixes #29946
PouleyKetchoupp 5 years ago
parent
commit
1a9801f700
2 changed files with 19 additions and 0 deletions
  1. 17 0
      scene/main/scene_tree.cpp
  2. 2 0
      scene/main/scene_tree.h

+ 17 - 0
scene/main/scene_tree.cpp

@@ -78,6 +78,17 @@ bool SceneTreeTimer::is_pause_mode_process() {
 	return process_pause;
 	return process_pause;
 }
 }
 
 
+void SceneTreeTimer::release_connections() {
+
+	List<Connection> connections;
+	get_all_signal_connections(&connections);
+
+	for (List<Connection>::Element *E = connections.front(); E; E = E->next()) {
+		Connection const &connection = E->get();
+		disconnect(connection.signal, connection.target, connection.method);
+	}
+}
+
 SceneTreeTimer::SceneTreeTimer() {
 SceneTreeTimer::SceneTreeTimer() {
 	time_left = 0;
 	time_left = 0;
 	process_pause = true;
 	process_pause = true;
@@ -611,6 +622,12 @@ void SceneTree::finish() {
 		memdelete(root); //delete root
 		memdelete(root); //delete root
 		root = NULL;
 		root = NULL;
 	}
 	}
+
+	// cleanup timers
+	for (List<Ref<SceneTreeTimer> >::Element *E = timers.front(); E; E = E->next()) {
+		E->get()->release_connections();
+	}
+	timers.clear();
 }
 }
 
 
 void SceneTree::quit() {
 void SceneTree::quit() {

+ 2 - 0
scene/main/scene_tree.h

@@ -61,6 +61,8 @@ public:
 	void set_pause_mode_process(bool p_pause_mode_process);
 	void set_pause_mode_process(bool p_pause_mode_process);
 	bool is_pause_mode_process();
 	bool is_pause_mode_process();
 
 
+	void release_connections();
+
 	SceneTreeTimer();
 	SceneTreeTimer();
 };
 };