PSA: Don't use Instance.new() with parent argument

For those of you wondering how to find all cases of where you may have done this, search your game with this:

Instance.new\([\s\S]*,

Make sure you check “Regular expression”

This used to be necessary to avoid having WaitForChild hang itself when parenting AND THEN renaming (now fixed I believed)

56 Likes

There are many issues with parenting early which are not simply performance benchmarks. A while ago I ran into an issue where I had parented a part to workspace with the surface type defaulted to studs, upon parenting the engine had automatically created snap joints with the baseplate. Immediately after I set the Parent I would also set the surface types to smooth but since the snaps were already made and they stuck around. Ultimately, my projectiles ended up a little more stationary than intended…
This anecdote may have changed in our iterations of the physics solver, but I think it still serves as a good lesson!

9 Likes

I uh… You may want to fix that in RbxUtility. That’s substantial.

3 Likes

Here is a PR which does this:

2 Likes

I used option two religiously and started trying and learning option 3 because I find option 1 to be the unwanted method of doing things.

I’m a little frustrated with not being sure what to do about this now, but it could explain some recent lag since a gun framework we use in my clan has the create method. I’m just hoping there’s going to be a optimization at some point for whatever is going on because I’m still in the process of learning new things roblox added on my very long break.

It seems to be okay with StringValue or IntValue though. That’s mostly what I do when I’m instancing objects with the parent argument.

11 Likes

This makes sense, there aren’t nearly as many listeners needed for Value classes.
The part class has a ridiculous amount of members.

7 Likes

What if I am creating new instances within created instances, even after I set its properties? For example, if I am creating a GUI like this:

local Gui = Instance.new("ScreenGui") local Frame = Instance.new("Frame") -- Give the Frame properties Frame.Parent = Gui local TextLabel = Instance.new("TextLabel") -- Give the TextLabel properties TextLabel.Parent = Frame

Would it be better for me to set the parent of “Gui” to CoreGui after I create all of its children, or would it be better to set its parent first,before I create all of its children and parent its children to it (i.e. ‘Gui = Instance.new(“ScreenGui”, game.CoreGui)’ would replace the first line, as opposed to sticking ‘Gui.Parent = game.CoreGui’ at the end)?

4 Likes

Calling Instance.new with the second argument isn’t the root problem here.

The root problem is that setting Size has a side effect where it runs an extremely expensive collision check to make sure that it doesn’t intersect with nearby parts.

The overhead from resizing becomes worse is in the vicinity of other parts, presumably because the narrowphase of the collision check is really slow. My workstation (i7-4790K, 1070) was struggling to push 5 FPS when I had to resize big parts for the devforum offices.

Is this a good enough excuse to get rid of that behavior?

31 Likes

I always thought this was obvious. Once any instance enters the DataModel, it becomes “tainted”, in that anything might happen to it at any time afterwards, even after it gets removed from the DataModel.

This is why it’s impossible to program gear correctly. This is why using the index operator to get the children of an instance is bad practice. Scripts have no means to acquire ownership of an instance, even temporarily.

So, the solution, when creating an instance from scratch, is to make sure the script has initialized it to complete satisfaction before allowing it to enter the game. And to stop trusting any bit of information it contains from there afterward. Instances should never be used to contain important information; that’s what variables and tables are for. An Instance itself is merely a frontend for whatever effect you want it to have in the game.

17 Likes

Parts are created at the origin, so your assignment of CFrame isn’t actually doing anything. Try changing the CFrame to something like 100,100,100 and you’ll probably get a significant speed loss.

aiight

17 Likes

We can use string patterns in tye find widget?? Awesome!

I’ve rewritten Instance.new a bit using that “wait until thread yields” idea.
It’s almost as fast as setting .Parent as last field, much faster than the regular Instance.new(class,parent).
(I said “until thread yields”, but it’s more like “after all pending threads yielded”, can’t do better)

Here’s the (test) code, along with the output of running it 5x: Instance.new() with parent argument - Pastebin.com
Here’s a test run:

0.00053739547729492 -- Instance.new(a) setFields() setParent()
0.075802326202393 -- Instance.new(a,b) setFields()
0.00056886672973633 -- custom_new(a,b) setFields()
nil -- parent of custom_new(a,b) right after setting the fields
Folder 0.0021722316741943 -- parent + passed time after obj.Changed:wait()

Basically, add the end of the tick, it (only then) sets the parent of all custom_new(a,b) objects.
The “mutex function” only runs once, at the end of the tick that mutex:Fire() got called.
So after wait()or coroutine.yield(), the parent is guaranteed to be set to what you wanted.
Seems like it’s almost as fast as setting the Parent afterwards, but Parent is only set after a semi-tick.
You can also do mutex.Event:wait() if you need to wait until everything (of the current tick) is parented.

TL;DR: “Fixed” Instance.new(a,b), but Parent is only set somewhere before the next tick
(it’s still better to just manually replace all Instance.new(a,b) with a variant that sets .Parent afterwards)

One thing I noticed:
Instance.new("Part",workspace) takes longer depending on how many parts are already present.

2 Likes

Does the advice to not use the parent parameter apply to cases where the parent is not a descendant of the DataModel?

E.g., is this okay?

local p = Instance.new("Part")
local f = Instance.new("Fire", p)
f.Heat = ...

Is the DataModel itself where the performance problems come in? Or do descendants in general cost here?

1 Like

As long as it isn’t a descendant of game, it’s ok.
If your part p would be a descendant of game, it wouldn’t, but that isn’t the case here I think.
So you can create one object, keep adding objects to it and not care about this, then set the top object’s Parent.

1 Like

This is very useful information. Thanks for sharing with us!

2 Likes

The difference between parent/property assignment order for this code exists but is pretty small and unlikely to be measurable unless your hierarchy is much deeper. The main issue is with parenting to game.

4 Likes

So the problem isn’t necessarily with the parent argument, it’s just that changing certain properties of things parented to game can cause performance issues?

1 Like

This explains some things…