Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Memory management for large amount of textures

Discussion in 'Scripting' started by TOES2, Sep 20, 2013.

  1. TOES2

    TOES2

    Joined:
    May 20, 2013
    Posts:
    135
    I am making a 3D book. Each page has a high-res texture, and the entire book might consist of as much as 100 pages in total.

    Although there is a large number of textures in the entire book, I only need at max four textures in memory at any given time (two for the page being flipped, two for the pages in the background). The other pages will be hidden.

    What is the best practice for making sure Unity does not try to load or keep all 100 hires textures in memory at the same time in a worst case scenario?

    At the moment, I am providing the page textures as

    Code (csharp):
    1.   public List<Texture2D> pageTextures;
    in my book script, which is populated through the Inspector. The script ensures only four textures are actually being used from this list of 100 at the same time.

    But, I feel worried as I do not know what Unity is doing behind the scenes here. Will it automatically load and unload textures as I assign and unassign them to the relevant page materials (only four materials exists in the scene)? Or do I need to manage this manually, and if so, how?

    Using Unity Free by the way.
     
    Last edited: Sep 20, 2013
  2. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
    to make sure you only have required textures in memory use resources.load when a texture is required and manually "destroy" it when done (assign null to all references).
     
  3. TOES2

    TOES2

    Joined:
    May 20, 2013
    Posts:
    135
    But I thought unity will only include textures it flags as used, so if I load them directly from the assets in a script without having any references to them in Inspector fields, will they still be included?

    Edit: Never mind, that is what the special Resources folder is for...
     
    Last edited: Sep 20, 2013
  4. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
    vs.
    now i'm confused. i don't know when the asset engine loads and unloads the data. thats why i sugested to use resources to have full controll over the process when it worries you. or you could still "profile" it by running your approach and checking the used memory of the application in windows task manager.
     
  5. TOES2

    TOES2

    Joined:
    May 20, 2013
    Posts:
    135
    Yes, I was hoping to avoid having to do that though by asking here for what the best practice is based on how Unity operates in the background. I do not know how smart Unity is when it comes to unloading textures that are referenced but not actually used in the scene. Seems to implement my own texture caching system is a bit overkill, but better safe than sorry, so I will just do that.
     
    Zinov likes this.
  6. Dave-Taylor

    Dave-Taylor

    Joined:
    Jul 7, 2012
    Posts:
    21
    I'm doing something very similar. The problem with using Resources.Load() is that you get a hitch anytime it happens, which will make your book feel jerky every time it loads a page, but it's really the only way forward for you running Unity free.

    If on Pro, the temptation would be to use AssetBundles, but the problem is that AssetBundles starts with "ass" for a reason. They're a huge pain in the same to maintain, particularly if developing a cross-platform app. I also found the performance loading from them pretty abysmal, too. In the end, I spent a lot of time getting these working, and then I ripped it out.

    What I'm doing now is going to sound a little circuitous, but I think it's the best way forward. I'm putting each page into a material, and then I'm putting that material onto a quad, and I'm storing the quad on an object in a scene by itself called page1.unity, page2.unity, etc, and then I'm doing an Application.LoadLevelAdditiveAsync() to load it into the app asynchronously, pulling out the material, turning off the renderer, and then destroying scene's page object when ready to unload. The scene files are pretty small, about 10k each.

    I believe this might be the best way for you to approach it. Just use a LoadLevelAdditive() to pull them in, and then when/if you upgrade to Pro, it should be easier to migrate to loading them asynchronously.
     
  7. stevesan

    stevesan

    Joined:
    Aug 14, 2011
    Posts:
    65


    I'm curious as to what issues you ran into with asset bundles. With some quick tests, asset bundles seem to work quite well if you use LoadAsync. Of course, it depends on how large your texture is - if it's only 5 MB, then yes, you'll see a hitch no matter what (due to uploading to GPU, I think). So I'm a bit surprised asset bundles didn't work for you where separate scenes did. Details?
     
  8. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,509
    That's not really true. AssetBundles are Pro-only, but they're actually only useful for pretty specific cases, and loading images isn't one of them.

    I'd suggest looking at System.IO (I think) which is a part of the .NET/Mono standard library, and also at the WWW class which can be passed local addresses ("file://...") as well as remote ones.
     
  9. stevesan

    stevesan

    Joined:
    Aug 14, 2011
    Posts:
    65
    So I have been implementing a texture streaming system for our game, and actually, things have been working out quite well so far. Still some wrinkles to polish off, but I plan on writing a blog post series once it's done and tested.
     
  10. jonc113

    jonc113

    Joined:
    Mar 10, 2013
    Posts:
    18
    Although I'm not an "expert", I don't see anyone giving what I think is the correct answer, so I'll venture forth.
    Assuming the free version (no asset bundles), the only way to limit memory is to use the Resources functions.
    However, as Dave Taylor said, you will get a "hitch" when it runs. Also loaded resources stay in memory until they are unloaded.

    So, I recommend:
    1) Load the page texture, using Resources.Load
    2) While your readers are reading that page, load the previous and next pages in a coroutine, so they are ready to go when needed.
    3) Be absolutely sure to Destroy old textures AND use Resources.UnloadAsset to free up that same resource texture from memory.
    Unity doesn't do it automatically.
     
    Last edited: Jan 26, 2014
  11. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,716
    I don't know of any method named LoadAsset.

    There's a LoadAssetAtPath, but it is Editor Only.

    Did you mean Resources.Load?

    To reduce "hitch" or "hang", I would split a page texture into smaller chunk and load one chunk per frame. Sadly, Unity doesn't appear to offer any asynchronous way to load local data.
     
  12. jonc113

    jonc113

    Joined:
    Mar 10, 2013
    Posts:
    18
    Yes, I meant Resources.Load (I fixed the original post) - and can't you just use a co-routine to load asynchronously?
     
  13. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,716
    Coroutine are not asynchrone, sadly. Coroutines are updated the same way MonoBehaviour "Update" method is. Unity is not really multi-thread friendly.

    However, I did find something that is a kind of hack for loading asynchronously; http://docs.unity3d.com/Documentation/ScriptReference/Application.LoadLevelAdditiveAsync.html

    It requires Unity Pro and to package your data within scenes. Bleh.