Question with a Resource Manager.

closed account (N36fSL3A)
I think I'm almost done with my resource manager.

I can load resources I need upon request, and unload them... the problem is, I'm trying to figure out when I should unload them. I can easily just call the unload function and reference the Resource pointer's ID, however I don't want to forget and use memory when I don't need to.

So I've been thinking of a sort of timer... A resource would be in the memory for a certain amount game cycles, if it's not referenced within that time, we simply unload it.

There's one problem with this however. What if the resource is expensive to load, and I reference the resource 1 cycle after it's unloaded. That's going to cause massive amounts of lag.

I hope one of you seasoned programmers can help me out with this.
Use a reference count to track how many references a resource has. Decrement the ref count whenever an object referencing it gets destroyed and free it when the ref count reaches 0.
closed account (N36fSL3A)
Use a reference count to track how many references a resource has. Decrement the ref count whenever an object referencing it gets destroyed and free it when the ref count reaches 0.
I was planning on doing that, but I don't want it to run out of references one cycle and then be referenced again, reloading an expensive resource...

There's also that chance I forget to free my memory, and it keeps that resource in memory...

Maybe I should give it a few cycles afterwards to make sure it isn't referenced...
Last edited on
If you are tracking references, then your reference count will only drop to 0 when the resource is no longer being used. At least... that would be the case if you're doing things properly.


-) Things that need to use resources need to "hang on" to them for as long as they're being used. IE, a sprite should not re-acquire a texture every time it draws... it should acquire it once when it is created, then hang on to it until it is destroyed.

-) If everything that is being "hung on to" is reference counted... this means that as long as a reference count is nonzero, something in your program is still using that resource and you should not free it. Once the reference count drops to zero, you know that nothing else is using it, and you can unload it. (RAII helps with this... just give your Sprite/Object class a shared_ptr to its texture... then let the dtor destroy it thereby automatically releasing the reference).

-) std::shared_ptr already does reference counting, so you don't have to reinvent the wheel here. Your manager can own one shared_ptr to the resource, and it can feed back copies of the shared pointer back to code that needs to acquire resources. You can then use shared_ptr::unique (from within the manager) to determine whether or not it has the only remaining copy of that pointer. If unique() is true, you know nothing else is using that resource.

-) The downside here is that unloading will not be automatic. There's no [easy] way to automatically notify the manager that you are no longer using a resource. So you might have to periodically (like say... every 5 mins) "poll" the resource manager to have it scan its currently loaded resources... and unload all the unique ones.
Last edited on
closed account (N36fSL3A)
-) std::shared_ptr already does reference counting, so you don't have to reinvent the wheel here.
Right when I do reinvent the wheel, :P.

-) The downside here is that unloading will not be automatic. There's no [easy] way to automatically notify the manager that you are no longer using a resource. So you might have to periodically (like say... every 5 mins) "poll" the resource manager to have it scan its currently loaded resources... and unload all the unique ones.
How exactly would I find out of 5 mins passed without getting into threads?
closed account (o1vk4iN6)
How exactly would I find out of 5 mins passed without getting into threads?


time() ? Or game ticks ?
Last edited on
How exactly would I find out of 5 mins passed without getting into threads?


You could just do it every few hundred/thousand frames. Like just modify your game loop:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
while(game_running)
{
    processevents();
    updatelogic();
    renderscreen();

    // add this:
    --counter;
    if(counter <= 0)
    {
        resman.unload_old_resources();
        counter = 100000;
    }
}
closed account (N36fSL3A)
Figured out how to make it 5 mins, thanks for that though.

I just googled how many miliseconds were in 5 mins, and then I modified my resource manager to be required to be updated, and it checks if it passed 300,000 miliseconds, if it did, check if the stuff isn't loaded.
Is it possible to predict ahead of time when a resource will be coming into or going out of scope? Like a map entity that is several screens away...

Or if the problem is tying up the input/render thread then IMO you shouldn't be loading such expensive resource like that. You could resort to asynchronous IO or a separate thread to do the loading and unloading.
@knn9
If the player can only go in one direction (like Mario) then you can just release textures as soon as they go off screen. If the player can go backwards, though, then you can't predict it because you won't know which direction they're going to go.

You could split your map into sections, each section having its own list of resources that need to be loaded. Let's say the player begins at section 0. You would immediately start loading the resources for section 1 in a background thread so that they're loaded by the time the player reaches section 1 (if loading is not yet complete you can put up a loading screen). You would also keep the resources for section 0 loaded so that the player can go back without another loading screen. You only release the resources for a section when the player can't immediately get back to it (i.e. if it's not directly adjacent to the current section). That way you always have the current section, plus both adjacent sections, in memory. Some downsides are that it can use up a lot of memory if your sections are all unique (but if there's a lot of shared data then it won't use as much), and that you can still end up pointlessly reloading things if for example the player moves from section 0 to 2 and then back. I'm going to avoid the latter with a caching algorithm that keeps textures in system memory when they're first loaded and copies them into video memory when a new section is loaded instead of loading them from the disk. The textures will also be stored alongside a timestamp of when they were last copied to video memory. When the cache, whose size will be fixed at runtime, is full, the resources that have gone the longest without being used will be released. I'm only going to cache textures because (1) they're the only resource that can be in two different kinds of memory at once, and (2) sound effects, music and shaders will be much more shared between different objects and sections and so they won't be moving in and out of memory as often as textures will be.
Last edited on
closed account (N36fSL3A)
I was trying to stay away from multithreading, but I guess I was eventually going to have to look into it...

chrisname wrote:
You could split your map into sections, each section having its own list of resources that need to be loaded.
That's a great idea.

Sorta like chunks in Minecraft (I also noticed GTA San Andreas did the same thing)... The reference system should go hand in hand with that, and the polling system aswell.

I think this is solved.
Lumpkin wrote:
I was trying to stay away from multithreading, but I guess I was eventually going to have to look into it...

Well, not necessarily, you could use async IO instead but you're probably going to have to use threads soon enough anyway.

Sorta like chunks in Minecraft (I also noticed GTA San Andreas did the same thing)

Lots of games do it. TES games and Fallout 3/NV call them cells. I think Half-Life 2 does it as well, except that it doesn't seem to load objects in the background because the loading screens can be quite lengthy.
Topic archived. No new replies allowed.