ScriptableObjects "save memory" How?

In many talks and presentations, the claim is made that ScriptableObjects save memory over having things saved in prefabs.

Yet, so far as I can tell, for a prefab instance to then ingest and locally use the values or properties of a prefab, it must have variables/properties it can set to the values stored in the ScriptableObject.

To my (limited) thinking, this would mean there is no memory saved.

What am I missing or misunderstanding about the claim that ScriptableObjects save memory?

Basically if every monster prefab has ten variables (BaseHealth, BaseMana, BaseStrength, BaseIntelligence, etc.) versus every monster prefab having one variable referencing the ScriptableObject that has those ten pieces of information.

2 Likes

So the SO acts as a struct, stored in the memory of each instance?

With a member for each value?

And that’s more efficient?

btw, sorry if I’m asking stupid questions.

I use SO’s quite heavily for something that others might use Animator States for, and that’s always made a lot sense, to me.

But using SO’s as a kind of reference house for Prefabs, rather than just serializing variables in Prefabs, has always been claimed to be more efficient in terms of memory, but I’ve never quite understood how or why that might be the case.

No, they’re not structs. Structs are value types. ScriptableObjects are classes, and thus reference types. What’s the difference?

Perhaps this chart will help illustrate the difference of each monster keeping a copy of the data versus referencing one shared set of data:

Then just extrapolate it to an extreme:
1000 monsters each with their own copy of 100 pieces of data = 100,000 pieces of data stored in memory (1000 x 100) versus 1000 monsters each with 1 reference to 100 pieces of data = 1100 pieces of data stored in memory (1000 x 1 + 100).

5 Likes

Ok, but each Monster instance needs to store its strength, it’s health, it’s endurance, etc, locally, so it’s made a new storage variable/property for each of these values.

So I don’t see any memory saving.

Am I still missing something?

I don’t see why it would need to store local copies of immutable data like strength or endurance, only mutable data like current health, which isn’t the same as maximum health anyways. Even still, there’s lots of other data (movement speed, attack radius, detection radius, team banner, team faction, AI aggressiveness, AI tick rate) that could all be relevant data outside of things you’d consider “gameplay” values.

2 Likes

Let’s imagine a game where Strength and Endurance have current, local values inside each monster, along with nutrition level, health level, etc.

Why isn’t it better to just have these public, and set in the prefab, to their initial values, than having an SO set these initial values?

I think the bigger misconception here is comparing ScriptableObjects to prefabs on the narrow job of keeping values alone, rather than what each thing actually is. If you have the time, give this video a watch. If you’ve already seen it and still make the case prefabs are just as good as ScriptableObjects, consider that your project is simple enough to not involve ScriptableObjects.

1 Like

Have watched that video.

Please, in simplest, most communicable and easiest understood possible terms, how would Scriptable Objects be best used to save memory over using Prefabs?

Rather than casting aspersions about what my project is, please try to help me understand what can be done best with ScriptableObjects, and why.

Never used them but from reading here I would say it would be the same as having static data holding base values. For instance I use a static class to hold values that a bunch of things grab from. A SO wont save memory in this case but is the same concept I believe.

public static int NumberOfLegs(Types type)
{
    switch(type)
    {
        case Types.Humanoid:
        return 2;
        case Types.Dog:
        return 4;
        default:
        return 0;
    }
1 Like

I think @GroZZleR 's graphic explained it quite well. Instead of duplicating the same data on each instance, you save it only once in a scriptable object.

But I don’t think that will be very significant in most cases, game data usually won’t make up most of your game, textures and audio will use much more space.

There’s also an additional but now a bit outdated consideration: Scene file size. Unity used to keep the full prefab instance in the scene file, so using lots of prefabs would actually not reduce your scene size at all. Now Unity only saves the prefab modifications in the scene file but just the standard overrides can take quite a bit of space per instance (about 2.5k bytes at least). Putting and sharing more data in scriptable objects will move the data out of your scenes and can reduce their size.

1 Like

Ah, yes; in this instance it would save memory over having a static class because it could be separated by scenes and may not need to be in memory. But will it be able to pull data during a declare as I often enjoy?

Absolutely agreed. If there’s ANY saving, it’s tiny base types.

But just using the approach of @adehm or Managers seems to match or better ScriptableObjects in terms of memory benefits.

Perhaps.

A long time ago, I switched to using Prefab Proxies (term of my own making, some might call them imposters or placeholders) in Scenes, to be the Editor visual representations of the positions of Prefabs. At game start (or entering Play Mode) a Manager class goes through and replaces all the proxies with the correct Prefabs for that level.

This approach radically decreases the time it takes to enter Play Mode, as there’s no need for Unity to copy across all the Prefabs, instead it runs as a game might, with freshly instantiated Prefabs in the level locations pertinent.

The only times I use the full blown Prefabs in the Levels inside the Editor is for aesthetic consideration needs.

Hopefully an example will help. Say your game has 3 orcs with minor variations, the only difference between them is their name, texture, and some stats. You could create 3 different prefabs and call it a day, but no, you’re a stickler for space.

Instead you have 1 orc prefab, and create 3 ScriptableObject instances holding the name, stat variation, and material. In your orc spawner, when you instantiate the orc prefab, you assign it the relevant ScriptableObject instance and call a custom initialize function.

On the surface, from a script perspective this looks like more work. In the prefab version, you assign your spawner 3 prefabs and spawn the relevant one. In the ScriptableObject version you need to assign 1 prefab, 3 ScriptableObjects instances, and still have to make special provisions when spawning an orc.

In data however, 3 prefabs hold 3 gameobjects, 3 transforms, 3 monobehaviors, 3 MeshRenderers, basically 3 of everything to make an orc whole. The ScriptableObject version holds 1/3 the data by having 1 prefab, and keeps relevant data in 3 ScriptableObject instances.

This is why people say ScriptableObjects are more efficient with holding data. Prefabs potentially hold data you do not really need to be keeping.

I find the choice of using ScriptableObjects in its most basic form, boiling down to 3 questions:

  • Do you need to only hold a bunch of data with nothing else?
  • Do you need this data to be referenced throughout the game?
  • Will this data need to be referenced quickly and regularly?

If no to some, maybe a prefab will suffice.
If yes to all, ScriptableObject is an option.
The sad part however, is answering these questions isn’t as obvious as it seems. Again using the 3 orcs example, 3 prefabs would have been a perfectly reasonable assumption due to its simplicity in implementation. The simplicity of the implementation however, came at an unforeseen cost of duplicate components being stored.

And this is just one example of a space benefit for using ScriptableObjects. You will need to study further on what ScriptableObjects can do, in order to fully appreciate why it is in Unity at all. It can help with pipeline and design with enough creative use.

1 Like

Now more confused than ever. Sorry.

In the above scenario, why not use Prefab Variants?

But let’s put that aside for a moment, because there’s a bigger issue, I think, and the main reason I can’t see how this saves any memory.

Please, let’s focus on the Texture, since it’s the largest item in memory.

Regardless of methodology (SO or Prefabs), that Texture has to be stored on/in SSD/HDD storage of the target build device, within the game’s “app package”.

Prefab Materials reference this texture, so it’s not copied around storage memory even if it’s used in multiple different Prefabs and their materials, and can be referenced as many times as needed without increasing memory usage?

It must be loaded into GPU memory to be shown on the screen by the material’s shader, regardless where it comes from (SO or Prefab material reference)?

So, to my naive eyes, I don’t see how there is any saving of memory for the Textures, when using SO or Prefabs.

Am I still missing something, or making very wrong assumptions?

btw, there is a chance that I’m giving Prefab’s far more credit for their ability to reference (rather than copy and hold) materials and textures than they actually have.

In my example, there isn’t any memory being saved in terms of the materials and textures, since you will need at least 3 materials and 3 textures to visually reflect the orc variations.

I have absolutely no idea how to explain simpler than this. If you still cannot understand what I am saying after spelling it out this blatantly, I can’t help you.

This claim is what made me focus on the Texture, as I couldn’t see how this can be true for the single most memory intense part of the Orcs, which threw into doubt all your other claims.