How to fix memory leak and stack overflow in code

Godot Version

4.4.1

Question

My code is generally not working and having memory leaks, more specifically in the brick code, here is all of my code
Player:

extends CharacterBody2D
class_name Paddle
#above is the class of what instance this is

extends CharacterBody2D
class_name Paddle
#above is the class of what instance this is

#declares variales, these are useful
@export var SPEED: float = 1000.0
@export var deceleration : float  = 400.0
@onready var ball = $"../B A L L"
@onready var marker_2d = $Marker2D

#these variables are set later
var screensize
var is_launched: bool = false

func _physics_process(delta: float) -> void:
	screensize = get_viewport_rect().size
	if not is_launched:
		ball.global_position = marker_2d.global_position

	var direction = Input.get_axis("Left", "Right")
	if direction:
		velocity.x = direction * SPEED
	else:
		if velocity.x > 0:
			velocity.x = max(velocity.x - deceleration * delta * 10, 0)
		elif velocity.x < 0:
			velocity.x = min(velocity.x + deceleration * delta * 10, 0)
	velocity.y = 0
	position = position.clamp(Vector2(65, 0), Vector2(screensize.x - 65, screensize.y))
	move_and_slide()

func serve():
	if is_launched: return
	is_launched = true
	ball.set_physics_process(true)
	ball.global_position = marker_2d.global_position
	ball.velocity = Vector2.UP.rotated(deg_to_rad(-90 + 100)) * ball.ball_speed
	ball.rotation = deg_to_rad(-90 + 13)

func _input(event):
	if event.is_action_pressed("Launch B A L L"):
		serve()`

Ball:

extends CharacterBody2D
class_name Ball

@export var ball_speed : float = 700.0
@onready var raycast = $RayCast2D
var screensize

func _ready():
	#to prevent the ball moving instantly
	set_physics_process(false)

func _physics_process(delta):
	screensize = get_viewport_rect().size
	var movement = velocity * delta
	var collision = move_and_collide(movement)
	
	# Handle screen edge collisions
	if position.x < 0 or position.x > screensize.x:
		velocity.x *= -1
		position.x = clamp(position.x, 0, screensize.x) # Keep ball within bounds
	if position.y < 0:
		velocity.y *= -1
		position.y = 0
	elif position.y > screensize.y:
		#ball of the ground handling
		print("Ball went off the bottom!")
		set_physics_process(false) # Stop the ball
	raycast.enabled = true
	# Handle collisions with other objects (like the paddle)
	if collision:
		# Check if the colliding object is the Paddle
		if collision.get_collider() is Paddle: # Access the colliding body via 'collider'
			var distx = global_position.x + collision.get_normal().x
			var disty = global_position.y + collision.get_normal().y
			# Calculate bounce based on collision normal
			velocity = velocity.bounce((Vector2(distx, disty).normalized() - collision.get_normal()).normalized())
			
			if collision.get_collider().velocity.x != 0:
				velocity.x += collision.get_collider().velocity.x * 10 # Adjust factor as needed
			# Keep the ball moving at its speed
			velocity = velocity.normalized() * ball_speed
			
			print(collision.get_collider())
			print(collision)
		else:
			# Handle collisions with other potential objects like the bricks
			if collision.get_collider() is Brick:
				collision.get_collider().queue_free()
			velocity = velocity.bounce(collision.get_normal())
			velocity = velocity.normalized() * ball_speed

func velocity_set(new_velocity: Vector2):
	velocity = new_velocity

func is_ball():
	return true`

Bricks:

extends StaticBody2D
class_name Brick

@export var brick_color: CompressedTexture2D = load("res://Palletes/Brick_Red_Pallete.png")

@export var Rows = 5
@export var Columns = 10

@export var grid_array: Array = []
var scrnsize
var brick_width = 50
var brick_height = 10
var spacing = 10
var brick_pool: Array = []
var max_pool_size = 100  # Adjust this based on your needs
var brick_template: Node = null

# Initialize the brick pool
func initialize_brick_pool():
	if brick_template == null:
		brick_template = self.duplicate()
		brick_template.visible = false
		brick_template.position = Vector2(-1000, -1000)  # Move off-screen
		brick_template.name = "BrickTemplate"
		add_child(brick_template)
	
	for i in range(max_pool_size):
		var brick = brick_template.duplicate()
		brick.visible = false
		brick.position = Vector2(-1000, -1000)  # Move off-screen
		add_child(brick)
		brick_pool.append(brick)

# Get a brick from the pool
func get_brick_from_pool() -> Node:
	if brick_pool.size() > 0:
		var brick = brick_pool.pop_back()
		brick.visible = true
		return brick
	else:
		# If the pool is empty, create a new brick
		var brick = brick_template.duplicate()
		add_child(brick)
		return brick

# Return a brick to the pool
func return_brick_to_pool(brick: Node):
	brick.visible = false
	brick.position = Vector2(-1000, -1000)  # Move off-screen
	brick_pool.append(brick)

# Simple generator for bricks and other stuff in a simple grid
func generate(_delay: float, rows: int, columns: int):
	for row in range(rows):
		for col in range(columns):
			await get_tree().create_timer(_delay).timeout
			var brick = get_brick_from_pool()
			brick.position = Vector2(col * (brick_width + spacing), row * (brick_height + spacing))
			grid_array.append(brick)

func _ready():
	scrnsize = get_viewport_rect().size
	var material = get_node("Brick").get_material()
	if material and material is ShaderMaterial:
		material.set_shader_parameter("palette", brick_color)
	else:
		print("Error: No ShaderMaterial found on the Brick node.")
	grid_array = []
	initialize_brick_pool()
	generate(0.5, Rows, Columns)

# Optional: Function to clean up bricks
func _on_game_over():
	for brick in grid_array:
		return_brick_to_pool(brick)
	grid_array.clear()

Any help will be appreciated :)’

Also srry if the txt here is messy im new to posting here

If you put three backticks ``` on lines before and after the code, it will format more readably.

When are there memory leaks and stack overflows, and what are the error messages?

From the documentation on duplicate (emphasis mine):

Duplicates the node, returning a new node with all of its properties, signals, groups, and children copied from the original.

Inside initialize_brick_pool is a for loop. The first time it is executed, it creates a copy of the scene, then adds the copy as a child to the original scene. The second time the loop executes, it will copy the scene again. However, this time the scene has a copy of itself included, so that child scene is copied as well. Do this a hundred times, and you have a whole bunch of scenes with long chains of copies attached to them, all of which get added to the brick_pool array.

What you probably want is to add one brick without any children to the array every time the loop executes.

3 Likes

ok ill try that and ill say how it goes

stack overflow happens in brick_template = self.duplicate and bricks ready code’s initialize_brick_pool(), if thats helpful

Seems like you shouldn’t be using .duplicate for this, the node managing a pool of itself if a very strange architecture, wouldn’t it be easier to have a seperate node instantiate a pool of bricks?

Make sure to post updated code or it’s impossible to know why you are getting such or the same errors.