Monster shadow

VIDEO

Object Pooling in Unity 2021 is Dope AF

Description:
Unity has graced us with our very own built-in object pooling! I'll show you how to get up and running with it, show you the drastic performance boost it can provide as well as lightly touch on a few of the other pool classes like the GenericPool. Here's the base class I mentioned in the video: https://bit.ly/3nI3ubh ========= 🔔 SUBSCRIBE: https://bit.ly/3eqG1Z6 🗨️ DISCORD: https://discord.gg/GqeHHnhHpz ✅ MORE TUTORIALS: https://www.youtube.com/tarodev
ADD A COMMENT

SketchyCosmos
Fingers crossed this leads to a built-in, object-based, 3D "particle" system!
Can you not?
What's with that "Clash of clans" font?
Tarodev
The original font is called 'You Blockhead'. Clash just used it.
R69NiX
Why are you wearing that shit on your head though? Unless there's a cute or genuine reason, you look like such a bellend. Again if there's some reason then fair play, but if not then why?
Tarodev
You are thinking waaaaaaaaaay too deeply on this
Water Cat
i will probably will not change unity version yet but Object Pooling sounds very useful for optimization
Andreas
There is nothing this man is teaching I don't want to know.
Ege Atıcı
Instasubscriibbbbeeeee to your channel <3
biogic
Great video! Another performance tool to make that next great game. Thanks Unity and thank you for the video!!
Eugen Lutz
Damn, you're so adorable with there ears, instant like and sub 😁
Tarodev
Too kind 😊
Eugen Lutz
Okay, without them you're still adorable
MyView
My name is pool. Dead pool...
RTWrename
my perspective, just finished seeing a video were demonstrates that man are getting weak by the times, and then I see a dude explaining something with play hears in the head, dam, I am gona give him the benefit of the doubt
RTWrename
@Tarodev It does not man sorry, but no worry, nothing against you really, it was just a fucking coincidence, thanks for the tutorial it was worth it
Tarodev
I went and lifted heavy weights up and down right fter this. If that helps
MrSingh
Hey man, love than channel , love the content. There is one request can u tell us which Shader u use , i mean i love the material of those 3d + signs floating around in your videos , i really loved their material. Can u tell us which shader is this , or if it is custom can u make tutorial if you have free time. It will be appreciated. Thanks Love the channel
Tony Tran
I didn't even know 2021 Unity had object pooling. I created my own -_-" Thanks for the heads up!
FeverGames!
so this bad boy video is the one that destroyed my pc
Tarodev
Yup 😂
Shivendra P. Singh
Great explanation
Steve S
The ironic thing is that the GC itself is supposed to be a low level, generic form of object pooling in a way. The heap itself is a giant pool of memory where the objects taking up that pool can be anything. I suppose there's a good chance the method used to unpool an object can be a lot simpler. But it still seems silly that this memory managment optimization isn't done implicitly under the hood given we already have the language features to do GC without needing to think about it.
•.Renard.•
why this get recommend to me
Tarodev
Probably due to my silky smooth voice and cat ears
David Hunsicker
Idk why unity can’t simulate mobile devices using partial cpu gpu ram cap based on know speeds of each phone so you don’t have to test each one of the phones and software updates using cloud streaming…
_ Maxxx_
Nice vid - just one point of possible confusion: You say at about 6:37 that the array "Allocates enough memory to store those 10 objects" Of course this can't be true - it allocates sufficient memory to store _pointers_ to 10 objects. It cannot possibly know how big each object is going to be. (easy example is an array of strings - a string (in theory) can be 2Gb so imagine declaring an array of 1000 strings if it had to allocate 2G x 1000!)
Matheus Amazonas
​@_ Maxxx_ Yes, in the context of MonoBehaviors that's true. I just believe we need to be careful with the word "objects". Value types are objects (they inherit from System.Object), but they are not accessed by reference. I just wanted to add to your answer to avoid sending a message that "arrays never contain the actual data", which I've seen before and it's not necessarily true. Just to add to the list: structs are also value types and arrays of structs will contain the actual data and not pointers. Structs are objects, but they will not be accessed by reference.
_ Maxxx_
@Matheus Amazonas it sounds like I'm being pedantic, but I'm clarifying for less experienced Devs: All objects are accessed by reference. Value types such as into, float etc are stored by value (is stored directly in the array). But you would never look a value type, and here we are specifically talking about unity object pooling.
Matheus Amazonas
It depends on the type of the objects being stored in the array. If it's a reference type, you're correct. If it's a value type, it knows exactly how much space it needs.
MohanABK
5Head
Leonardo Ceballos
Been doing this for years - it's great that there is some built in functionality for it now.
Lord Darth Vader
If only I waited, instead of implementing my own shitty object pooler.
SEE ALL COMMENTS


Transcript:

unity has just released their built-in object pooling system in version 2021
object pooling is an optimization strategy allowing you to reuse
components instead of destroying and creating them each time
game objects lists and classes can all be pulled to save the garbage
collector's cpu cycles clearing de-allocated memory from the heap
object pooling is best used when a large number of objects are being spawned and
destroyed in a short period of time it's especially important when shipping
to lower end devices like mobile phones and tablets
let's begin so as pretty as that scene was with all
the effects and sounds and uh physics and stuff
they will just get in the way of this test so what i've done is i've just
changed it so 10 spawn
every 0.2 seconds without any effects and as soon as they collide with this
floor here they just get destroyed so let me just show you how i've actually
set that up so we've just got a reference to the shape prefab a the
amount that we're going to spawn and then in start i'm just starting a
repeating function uh where i just iterate over the spawn amount and then
spawn it set it to a random position uh in a unit sphere
and then i initialize it by sending in this function into the object and then
the object just caches that action and then when it hits the collada it calls
the action which uh destroys the object so that may seem a little bit weird like
why don't we just destroy the object from within the object but uh it'll make
sense in a minute so now if we press play
we'll see that it's just spawning and then colliding with the ground and being
destroyed but if we ramp that up to maybe 100
every 0.2 seconds we'll see that the
the system is starting to stress a little bit we're tanking down to about
20 to 30 fps and if we go to our analysis tools and
our profiler we will see that if we go on this spikes
here we'll see that we're actually allocating
uh let's see here so 39 kb of memory every 0.2 seconds 39
39 obviously that is i mean my computer's
handling it okay but on a mobile device device you would be carpoot
so uh let's let's fix that let's let's make this object pooled
so the first thing we will do is create a private object pool
and this will be of type shape because that is uh what i am using
and let's just call this pool and then in start here
let's make a new object pool the way pooling works is say
you've got a thousand objects that you need to instantiate every second right
if you're creating and destroying those objects
it causes a lot of garbage that the garbage collector has to come and clean
up right so instead of instantiating and
destroying them all the time how about you just instantiate them once and then
once they're done once you you've finished with them you disable it and
then when you need another one of those objects you just grab one that you've
already used and disabled and you just re-enable it right and then you put it
into the position that you need it and then away you go and you just keep
re-using these objects which means the memory is not constantly being
allocated and deallocated which means the garbage collector doesn't need to do
anything with it [Music]
so that's how it works and as you can see this function takes a create
function on get function a release function so these are all the actions
that we need to tell unity what to do with in order to pool our object
efficiently because they have no idea what object we're using we could just be
using a normal game object that we just need to instantiate destroy we could be
using a bullet like the bullet could potentially need to be
instantiated every single time to give it a launch velocity you know could be
using like boxes that need to be they could break or something and you need to
rebuild them who knows what it is uh you probably shouldn't be using
object pulling for that last one anyway so let's create our first required
function here which is the create function so this is what unity is going
to call when there are no objects in the pool
available so they need to create one so uh for our create function all we're
going to be doing is returning an instantiated
shape prefer right that's all we need to do to create
this okay so what's next it is the on get
function so this is the function that is called when we ask for an object
and there is one available in the pool okay so this one will take uh will
it return to shape right and with this shape what are we
gonna do well usually the the most basic form of
object pooling is disabling and enabling so what we can do is we'll say shape dot
game object set active true okay so now we've handled r on get next
one is on release so this one is when we're done with the object and we need
to give it back to the pool so this one will be
shape and then we'll do the same but in
reverse so game object set active and false
and the last one here is our destroy actions so
this pool will always spawn objects when we ask for them even if it's above the
maximum once we've spawned it and it goes to
return to the pool if the pool is already filled
it will destroy the object instead so for this one it's just going to be a
normal destroy function and it will put our shape game object
okay so we've got a few other things to fill out here before we're done this one
is collection check so basically you can save
cpu cycles by turning this off and what this does is if you
have an object that you've already returned to the pool
if you try to return that again to the pool uh
it'll cause some bad problems right so unity can handle this for you and they
and basically if you try to return this object that's already been returned uh
unity will say nope it's already in the pool let's just ignore it
but that takes cpu cycles so if you're sure of your code and you know that will
never happen you can check this to off to false sorry
and you can save a little bit of cpu time okay the next one is default
capacity so this one may seem simple if you know how an array works this by
the way under the hood this specific object pool uses an array so
if you know how an array works say you instantiate an array with a size of 10
it is allocating enough memory to store those 10 objects even if you've got no
objects in that array it is still holding enough memory to store the 10.
so and in addition uh resizing arrays
can be expensive okay so really what you want to do with with
default capacity is if you know there is only ever going to be 10 you should set
it to 10. if you think there might be 11 you should set it to 11. but there's
also the scenario where potentially in there could be 100 but most of the time
there's only 10 okay so if you set it to 10 that's cool as long
as your max size is 100 you can it will expand as it goes but that is expensive
because uh say you've got 10 and then you just get one more this array now has
to resize to 11 and then i might have to resize to 12 and 13 and 14 right and
that takes a lot of cpu cycles whereas you probably would have been better off
setting it to 100 to begin with so it didn't have to do
90 array resizes okay so play around with these numbers depending
on your needs of the game you may get better results starting at
small and letting it expand or starting it at the full size uh
it does seem kind of silly to uh start an array at 100 and then in your map you
may only use like two you know so you're still taking all the memory of 100.
so i'm going to set mine to 10 for now and then max size i'm also going to set
to uh actually i'll set that to 20. and then that is it that is how we
create our pool we've got our create function our get function our release
function and then our destroy function our collection checks which we've said
false because i'm pretty sure that this code will be just fine
10 capacity and then 20 max size cool
so we've created our pool
and now as it would as we're benchmarking these two let's create a
little serialized field here so we can change it in the editor
uh use pool okay
so then in our spawn function instead here
uh we're instanting it instantiating it we can say
are we using the cool if we are let's grab it from the pool
instead of instantiating so pool dot get and it is literally that easy
you you are just grabbing something from the pool
otherwise let's instantiate it right because we're not using the pool
and then this is why i am actually sending this uh action into the shape
because i want to handle this killing logic uh in the spawner okay because
it's easy for us to kind of just pass and see what's going on
so just just to iterate i'm sending in this
function into the shape and net so that it knows what to do once once it
hits that that ground
so then here we can say if
we're using the pool instead of destroying it let's do shape
nope let's not do that let's do pool release and then send in our shape
else we will destroy it because we're not using the pool
okay so if we go to our spawner and we make this 100 which i believe was what i
was using for that initial test right so this is without the pull
and if we go to our analysis and profiler
just let it run for a little bit and then go here we will see that it is
allocating 39 kb and if we go here we will see that it is
all in fact from instantiating almost from instantiating all right so
we can remove this uh this is 22kb of instantiating every 0.2 seconds so let's
see what we can do with object pooling to improve this outcome
get rid of that let's turn on cool objects and let's make the default
capacity to 100 and then 800. okay so let's give that a shot
and yeah if you remember last time we were tanking fps pretty bad right so now
we're staying around 60 70. so that's a massive improvement just on
fps if we go to uh our analysis tool here
and actually it'll be better if we reset it so let's reset it and then i will
pause it straight away right and so we should know that these
these first ones here uh we actually are instantiating our objects aren't we so
that the pool needs to fill up first so we can see here instantiate it's
allocating 22 kb of garbage and that will be the same for all of these here
but if we let our pool fill up to capacity
so let's just give it a few seconds and then we try again here we will see
that now there is no allocation happening on instantiate and we're just
activating which obviously doesn't need to allocate any additional memory
because we've already spawned the object all we're doing is enabling it
so as you can see like
my computer can handle both of these quite well but on a mobile device
saving that amount of memory on allocating and de-allocating will
significantly improve the performance of your game so as i talk let's just uh
just maximize this as it's a little bit prettier
so actually that's it's too chaotic for me
too crazy let's uh reduce that down to like five
yeah oh but it's so boring now that i've removed the effects
and little side note which i'll probably remove in the final edit so i made this
scene before i went to bed last night like right before i went to bed and my
brain felt the need to
imagine these falling teas all night long like i would wake up and
then i would go back to sleep to more falling tears so it may look pretty to
you but i just want to get this out of my face so
side note so
that is the standard uh object pool that unity has provided they also provide a
few other options they provide a linked pool
so a linked pool has a little bit of different setup but the difference
between an object pool and a lint pool is object pull stores their um
all the elements in an array so as i was saying before if you have a default
capacity of 50 even if you've got zero items in that capacity it's still going
to take the memory of the 50 elements right
a linked pool uh doesn't take any memory if there's no
elements in there but the downside is that it's it's more
expensive to manage basically it will be more effort for the cpu to grab them
from the pool and release them full from the pool so really uh
you really need to decide do you favor the memory here do you need
or every single little bit of memory that you can possibly pull out or do you
need better management on the cpu so that's
the difference there so unity has also given us a whole bunch
of other pools which i'll put up on the screen now and you can go look at them
individually they're all really amazing what i will do though is i'll show you
one more list that i think is absolutely amazing one one more collection sorry
so say you're just pretend this is the update function right um and we
actually why would i pretend when i can do it so that's silly so let's just make
the update function here okay say we are doing some kind of like
pathfinding logic right and we we need a list in this loop so my list
equals new list and this will just be like an
integer list right and then we're using the list here and
then it goes out of scope so uh the memory will be deallocated and the
garbage collector will come and clean it up so we're creating a new list whoops
we're creating a new list every single loop of update we can actually avoid the
allocation and de-allocation of this i mean technically you can just create
your list out here right but who knows you might have a you might
have 10 lists here you do really want to just create it here to not de-allocate
so what can you do about that well we can say my list now is not equal to a
new list but we can do this generic pool right and this will be of type list
integer and we can say get
and this will just generate a list of that type right
for us to use so now we can use this so let's say my list
dot add and let's just say 69 right just a random number
and then uh this will go instead of just letting it go out of
scope we can now say generic pool of type list inch
release my list so then this will release it
back to the pool right and we could release 10 lists here and then next time
that this is called it will grab one of the lists that we just released now
obviously we would still need to clear this list right we
we don't want to continue using this list we might not want 69 and then we
might want another completely random number
uh sorry i mean you might actually have to do this
dot clear but that should be a lot better than
allocating and dow locating the memory for the list itself
in addition you can actually use this to uh store your own classes so let's just
say this is my class and in here i'm going to have a string
called hello right so now we can actually
uh let's just remove this and i'll do it from scratch so
my class right i need a version of the i need a
version of my class and this is going to be from the generic pool of type my
class and i'm going to get it
and then in here i'm going to set my class dot hello equals
hello and then i'm going to release it again
so generic pool my class
dot release my class
and just to illustrate this let's set a breakpoint here
attach to unity and let's play it and here we go so we've grabbed our uh
first class from the pool and as you can see it is already constructed it right
and there's nothing in hello let's now set hello to hello
and then let's release it to the pool okay and now
on the next loop of update we have now grabbed another version of my class and
as you can see we've only got one in there so let's grab the one that we've
already made and set to hello and we'll just keep recycling this instead of
creating a new version of my class and then de-allocating it every single loop
so obviously you know you need to think about resetting the object if you need
to but generally it's going to be better than creating a new one and deleting it
every single time i hope you enjoyed it and i hope you learned something i'm
going to include a script down below of uh how i am setting up my object pooling
so basically i'm creating a script and i'm deriving from it
so then that turns my derived script into like a really easy object pooler
where i only need to override some of these functions if i need to
so check that out if you want and i will see you in the next video bye
you