godotengine / godotengine/godot

Setting theme_font_size_override on a Label node through GDScript causes a memory leak

Open
#109,751 1 comment 0 reactions 0 assignees View on GitHub
documentation needs testing topic:gdscript topic:gui
Dominant language
C++
Stars
117k
Forks
26.8k
PR merge metrics
PR metrics pending

Description

### Tested versions

- Reproducible on 4.4.1stable, master [ [commit](https://github.com/godotengine/godot/commit/42224bb750176560c515a875e50a1a25d5949ddb) ], 4.3.

### System information

Godot v4.5.beta (42224bb75) - Nobara Linux 42 (KDE Plasma Desktop Edition) on Wayland - X11 display driver, Multi-window, 3 monitors - Vulkan (Forward+) - dedicated AMD Radeon RX 7900 XTX (RADV NAVI31) - Intel(R) Core(TM) i9-14900KF (32 threads) - 31.16 GiB memory

### Issue description

Setting a theme_override_font_size through either .set or add_theme_font_size_override("font_size", size) results in a memory allocation for each unique set call that persists even after freeing the Label node. It seems insane that it happens consistently, but it does appear to be the truth, and triggers at least once for every unique size. It only seems to add memory the first time a font size override is made at a specific StringName, int value, regardless of whether it is being made on the same Label.

I have not tested if this occurs for other theme properties.

This does have pretty bad implications. I discovered this when trying to understand why some programmatically created labels in a project were adding ~70MiB to my memory usage for seemingly no reason, and tracked it down to this line.

### Steps to reproduce

Make a new scene with a Node2D, attach the following and trigger with Enter.

I could not get it to trigger the first time I ran the scene on a new project, but it works all subsequent runs.

```
extends Node2D

# Called when the node enters the scene tree for the first time.
func _ready() -> void:
pass # Replace with function body.

func _input(event):
if Input.is_action_just_pressed("ui_accept"):
print("before label spawn ", Performance.get_monitor(Performance.MEMORY_STATIC))
var label = Label.new()
label.text = "Test"
add_child(label)
print("after label spawn ", Performance.get_monitor(Performance.MEMORY_STATIC))
var size = 100
for i in range(100):
print(Performance.get_monitor(Performance.MEMORY_STATIC))
size -= i
label.set("theme_override_font_sizes/font_size", size)

await get_tree().process_frame
print("after resizing", Performance.get_monitor(Performance.MEMORY_STATIC))
label.queue_free()
await get_tree().process_frame
print("after freeing", Performance.get_monitor(Performance.MEMORY_STATIC))
```

### Minimal reproduction project (MRP)

N/A

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.