Search Unity

  1. If you have experience with import & exporting custom (.unitypackage) packages, please help complete a survey (open until May 15, 2024).
    Dismiss Notice
  2. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice

How to check if an asset is unloaded without loading it up again accidentally

Discussion in 'Scripting' started by Zergling103, Jan 5, 2019.

  1. Zergling103

    Zergling103

    Joined:
    Aug 16, 2011
    Posts:
    392
    In Unity you can unload an asset from memory using
    Resources.UnloadAsset
    . It appears that this is done asynchronously as it doesn't appear to pause the main thread (at least not very much, even for significantly large objects). For reasons I will explain in later, I need to know when the asset's asyncronous loading completes, or at least I need the ability to check if is is completed. However, it appears that you cannot check the object you just unloaded for signs that it is finished unloading because looking at the unloaded asset's properties will cause the asset to become loaded again, which defeats the point of unloading it in the first place.

    Is there a way to check if this asset is finished unloading without spooking Unity into loading it all back up again?

    You're probably wondering "why do you need to do this in the first place?" It appears that if you instruct Unity to load an asset via
    AssetBundle.LoadAssetWithSubAssetsAsync
    while the asynchronous unload operation is running in the background on that same asset (via
    Resources.UnloadAsset
    ), the two asynchronous load and unload operations will conflict and cause Unity to load the asset back in incorrectly. This results in assets being missing when the load operation completes (ie missing meshes, empty black textures, pink materials) instead of the expected behaviour of cancelling any conflicting unload operations before attempting a reload.

    Okay, no problem we can work around this right? Well, not really, as far as we can tell, unless you know something we don't.

    We're currently organizing requests to load and unload assets in a queue such that (hopefully) unloads and loads do not happen at the same time. Multiple objects can be requested to load at the same time. Multiple objects can be requested to unload at the same time. But never are they allowed to overlap (in theory).

    However, unless there is some weird method we don't know about, we cannot check to see if all of the queued unloads are finished before switching back to performing loads. Currently as a work around we just wait an arbitrary length of time and cross our fingers and hope everything has unloaded by then. Luckily Unity's API provides a way to see if a load has completed, so at least they got half of it right.

    Anyway, that's the situation. Is there a "isDone" equivalent for unloading somewhere?
     
  2. Madgvox

    Madgvox

    Joined:
    Apr 13, 2014
    Posts:
    1,317
    Are you sure? Unloaded assets become invalid null-ish objects, and aren't able to be used for anything, let alone automatically reloading the object from disk. This is backed up by the docs for Resources.UnloadAsset itself:

    Additionally, as the docs state, the newly (re)loaded asset will be an entirely new instance, unconnected with the old object. Such conflicts that you describe shouldn't even be possible, which makes me think that it's more likely that something is going wrong in your own code.

    If you are correct and there actually is some kind of conflict occurring between loading and unloading an asset, that sounds more like a bug where the unloading data isn't getting marked internally as 'destroyed' properly.
     
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,858
    I'm not sure if you really need that fine-grained level of control over loading/unloading, unless you have a need that I have never experienced in quite a few years of using Unity.

    Unity is pretty darned clever internally. If you are careful to "let go" of all references to an asset, it will be come eligible for automatic unloading with no further action from you. This automatically happens when scene changes occur, or when Unity runs low on memory when you try to load something else.
     
  4. daxiongmao

    daxiongmao

    Joined:
    Feb 2, 2016
    Posts:
    412
    Are those two APIs supposed to work together?

    Is it possible you are unloading a reference to the asset on disk instead of the instance of that object?

    Also unity overloads their equal operator. You could try just using if(asset) instead of if(asset == null) if your not already.
     
  5. joethephish

    joethephish

    Joined:
    Nov 16, 2013
    Posts:
    5
    Hey Zergling, what did you end up doing about this problem?

    I've been attempting to be using AssetBundle.LoadAssetAsync in conjunction with Resources.UnloadAsset to load and unload sprites (on a well known console platform) but having super weird effects of sprite turning white sometimes or getting an entirely arbitrary other texture.

    I suspect I'm getting the issues you describe. Although I haven't found anything anywhere that says that Resources.UnloadAsset is async?

    I also suspect that Resources.UnloadAsset isn't actually meant to be supported for individual AssetBundle assets? But that if not that, what? Is it impossible to unload individual AssetBundle assets? If that's the case it's a no-go for our streaming requirements.

    All of this has been as part a move to convert Resources to AssetBundles (because the console platform recommends it to keep update data small). But I'm seriously considering just going back to Resources and praying that we don't need to do a game update!