Environment:
Platform: Roblox App/Roblox Studio
Feature: Streaming
Date Encountered: November 2, 2023
Overview:
The streaming feature on Roblox is not consistently destroying objects or handling connections when objects are streamed out, which is different from the previously observed behavior. The change in behavior was not announced and has broken some of the components in-game out of nowhere.
Previous Observed Behavior:
The behavior of how objects are streamed out is not properly explained in any of the documentation I could find. So I did some simple multiple tests in different environments with over 20-30 objects and figured out that when an instance is streamed out, it would be Destroyed as “.Destroyed” event would fire as well, along with all connections being disconnected too. When objects are streamed in, a fresh copy is sent from the server and any changes made on the client(tags, attributes, properties) would reset as well. Relying on this behavior, I continued working on a project, and about a few days ago, those specific things started breaking randomly which were relying on this particular behavior.
Current Behavior:
So at this point in writing, when objects are being streamed out, they are not being destroyed, and there’s more. They do get removed from DataModel but it’s not the same as setting .Parent to nil. So essentially, if there’s a strong reference to that object, any connections related to the object will not disconnect and the object will not be garbage collected. However, if you do not have a strong reference, it will disconnect all connections and remove the object from memory altogether(.Destroying would still not be called in either case). When the object is streamed in, it’ll still be a fresh copy from the server with everything changed on the client reset regardless of how it was streamed out. The behavior is inconsistent because:
Example:
We have 2 different parts, one of them does something when a player touches it, and one of them does something when anything touches it. What will happen is the following:
local PartA = workspace:WaitForChild("PlayerHealthPad")
local ConnectionA = PartA.Touched:Connect(function()
-- We kept PartA as a variable to do magnitude checks when touched by a player or doing anything else with part
end)
local ConnectionB = workspace:WaitForChild("PartB").Touched:Connect(function()
-- do something
end)
Now, when PartA is streamed out, the ConnectionA will stay connected, and when PartB is streamed out, the ConnectionB will disconnect making this entirely inconsistent.
Lastly, if you’re using CollectionService to get the instances and also using streaming, the problem becomes worse as tags changed will reset when the object is streamed back in but in some cases, the connections will reset, and in others, they won’t.
I am attaching a repo file with this with a streaming radius set to 64, and two parts with pretty much the same example as mentioned above.
streaming_repo.rbxl (54.4 KB)
Expected behavior
Tbh, I am not even sure what the expected behavior is as none of this information is outlined anywhere I could find, honestly both of the ways have their own pros and cons but I would expect it to be consistent, either disconnect and destroy the object, or don’t disconnect anything. I’ll be waiting on a response from the team on this so I can change/redo stuff accordingly on how they’ll be going forward with this. Lastly, please outline the behavior as well. Misinformation or assumptions can lead to unnecessary memory leaks and potential problems.