Is this a memory leak?

I was writing new Shop UI and coding it and had a brain moment it stumbled upon me that my old code for Settings e.t.c can have a possible memory leak. Heres the Settings Code (Exit Button).

local tween = TweenService:Create(self.MainFrame, tweenInfo, {Position = UDim2.new(0.5,0,-.5,0)})
tween:Play()
tween.Completed:Connect(function()
 self.MainFrame.Visible = false
end)

The connection is never disconnected UNLESS TweenService automatically disconnects it when completed is done. or would this new Shop code have no memory leaks here is the closing button

self.MainFrame.Exit.Button.MouseButton1Click:Connect(function()
	local tween = TweenService:Create(self.MainFrame, TweenInfo.new(.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out), {Position = UDim2.new(0.5,0,.5,0)})
	tween:Play()
	self._closingTween = tween.Completed:Connect(function()
		self.MainFrame.Visible = false
		self._closingTween = nil
	end)
	self.MainFrame.Visible = false
end)

Is it good that I noticed this early on if it is a possible memory leak? I assume so, just want to be sure and hear from someone who may know. Thank you and looking at it now im going to make this a Util module script for basic UI handling. :slight_smile:

1 Like

Yeah, Good catch!
Tween.Completed:Connect won’t auto disconnect, so if you fire tweens repeatedly you’ll leak connections. Either call connection:Disconnect() inside your callback or use tween.Completed:Wait() and yes, pulling that logic into a UI util module is a smart refactor :wink:

2 Likes

why not just use :Once()?

1 Like

you’re totally right, overlooked that. :Once()

tween:Play()
tween.Completed:Once(function()
self.MainFrame.Visible = false
end)

Thank you for replying! I’ll refactor my code to use Utils which is a lot cleaner haha

1 Like

Not quite. Roblox will automatically disconnect the connection once the tween object is collected from memory. You can observe this using the following code sample:

local function f()
    local tween = game:GetService("TweenService"):Create(Instance.new("Part"), TweenInfo.new(2), { CFrame = CFrame.identity })

    local connection = tween.Completed:Connect(function(playbackState: Enum.PlaybackState)  end)
    return connection    
end

local connection = f()
while task.wait() do
    print(connection.Connected)
end

On the sample, f is called (not inlined (although it wouldn’t matter anyway)), and connection.Connected will become false after a while; you needn’t worry about the connection in this case; the engine would handle it for you

image

2 Likes