Search Unity

  1. Unity 2019.2 is now released.
    Dismiss Notice

Confusions about IResourceLocation and Addressables.Release()

Discussion in 'Addressables' started by sunfl0wr, Nov 8, 2019.

  1. sunfl0wr

    sunfl0wr

    Joined:
    Mar 11, 2015
    Posts:
    13
    First of all I don't even understand the reasoning about needing to call
    Addressables.Release() as I feel C# memory management should deal with that once nothing is referencing? Why was it decided this way? And wouldn't it been better to use IDisposable if you want release of resource to be explicit? You probably have some good reasoning behind it but it feels very unclear (especially when it's need and when it's not) to me and don't seem very C# and different from how everything else in Unity works.

    Now for a question related to Addressables.Release() it's a bit unclear (for me) what operations demand that I call Addressables.Release() and it's also unclear what happens to the object once I've called release on it.
    In my case it's about AsyncOperationHandle. I've got a function calling Addressables.LoadResourceLocationsAsync() to find all addressables mathching some labels. Once that's done I want to return the result - a list of IResourceLocation - back to the caller. According to the documentation I need to Addressables.Release() the AsyncOperationHandle returned from Addressables.LoadResourceLocationsAsync(). What happens to the list of IResourceLocation I got from the AsyncOperationHandle result?
    Will they be invalid after I release the handle?
    First I tried just copying the PrimaryKey but realised pretty quickly that wouldn't work as Addressable allow for multiple addresses to share the same PrimaryKey... so I was forced to use IResourceLocation.

    Now for my next problem, if IResourceLocation is the closest thing to unique identifier for a resource inside Addressable, what's the best way of serialising this in my save file? Would JsonUtility's ToJson()/FromJson() be able to handle IResourceLocation?
     
  2. DavidUnity3d

    DavidUnity3d

    Unity Technologies

    Joined:
    Nov 17, 2016
    Posts:
    91
    Hey @sunfl0wr

    Release() is used to help manage a reference count to the underlying AssetBundles that Addressables is built on top of as well as handle when dependencies for a given asset aren't needed anymore. When an asset is loaded an AssetBundle is loaded and then the asset is extracted from that bundle. If that asset has dependencies on other AssetBundles those too will be loaded into memory and the assets extracted. It's not a matter of cleaning the loaded object in memory out of memory, it's for use with our resource management system that handles when and what AssetBundles are unloaded. Release will also help cleanup anything (instantiated objects, objects loaded into memory, or other data) that was created as part of the operation.

    There are definitely some operations like this that are confusing. Ideally you should call Release on any operation, though that has been a point of discussion since some operations it doesn't make sense for. Some APIs allow an optional parameter to auto release the handle after it has completed. Without looking at it explicitly I'd say yes, the IResourceLocations that are the result of that operation would most likely be invalid. If you're seeing different behavior let me know because I'd be curious to see (not all operations are created equal).

    Mostly likely you could serialize the ResourceLocationBase to Json. Everything in there that I can see looks like it would serialize to Json fine. I haven't tested it though.
     
    sunfl0wr likes this.
  3. sunfl0wr

    sunfl0wr

    Joined:
    Mar 11, 2015
    Posts:
    13
    Thanks for the answer!

    Actually I tried adding the results (the list of IResourceLocation) from AsyncOperationHandle to a new list and then release the operation handle. After that I used my list of IResourceLocation to load the assets using
    Addressables.LoadAssetAsync() without any problem. This could of course be pure luck that it worked, but it did work. So it would be good to get this verified, wether it I can do it this way or if I need to keep the AsyncOperationHandle until I know I don't need any of the IResourceLocation objects anymore (which would be at the moment I unload the asset the IResourceLocation was pointing toward, as I need a way of knowing where the asset came from when serialising/deserialising).


    Is it guaranteed that every IResourceLocation object is a ResourceLocationBase so it's safe to cast? Mainly wondering as LoadResourceLocationsAsync() returns IResourceLocation
     
  4. DavidUnity3d

    DavidUnity3d

    Unity Technologies

    Joined:
    Nov 17, 2016
    Posts:
    91
    Hmm, interesting. I'll double check how some of that works and try and get a solid answer for you.

    No, that is not guaranteed. We currently have two classes that implement IResourceLocation and one of them I don't think will serialize nicely. Given this, IResourceLocations.Dependencies also might not serialize cleanly depending on their concrete implementations.

    May I ask what is your use case for needing to serialize these? I'll try and help with finding a viable solution if I can.
     
  5. sunfl0wr

    sunfl0wr

    Joined:
    Mar 11, 2015
    Posts:
    13
    Thanks again :)

    So I'm currently updating our code base from previous game to use Addressable instead of
    Resources.LoadAsync()
    The game is a adventure/visual novel style game where much of the logic is written in a custom scripting language. Inside the scripts we specify what images should be displayed on the screen etc. This require a way of finding a asset and loading it and and rendering on screen. We also need to be able to save the current state of the game session and load it back later (e.g. we need to save what images are currently being rendered as well as any dialog and where in the story we are). Previously we used
    Resources.LoadAsync() and just saved the path of the image as a string, this wasn't any problem because paths were unique. But with addressable, the address/PrimaryKey isn't unique, multiple assets can have the same address, even within the same group as far as I can tell. So my best bet was to somehow use IResourceLocation
     
  6. sunfl0wr

    sunfl0wr

    Joined:
    Mar 11, 2015
    Posts:
    13
    I think part of my confusions regarding LoadResourceLocationsAsync() and IResourceLocation is that I should Release() the operation handle but not the IResourceLocation object.
    But on LoadAssetAsync() I should Release() the asset object (maybe I should release the operation handle as well?)
     
  7. DavidUnity3d

    DavidUnity3d

    Unity Technologies

    Joined:
    Nov 17, 2016
    Posts:
    91
    Hey, yes if you do a LoadAssetAsync you'll want to release that handle.

    If you have assets that are of the same type that have the same key how are you sure you're ever loading the correct asset? The way the ResourceManager should work is it will iterate through the resource providers and find the first one that can provide the resource given your type and key. Are you seeing something different?

    I would recommend making your keys unique if at all possible. Is there some reason that doesn't work for you?
     
  8. sunfl0wr

    sunfl0wr

    Joined:
    Mar 11, 2015
    Posts:
    13
    Thanks. In our previous system we had like a config file for each character containing categories of what how the character looked. E.g. if it was happy or sad. Within each category we had an ordered list of sprites.
    When selecting a sprite we would open the config file for the target character, find the category we were interested in and then the designer could either specify a index telling exactly what sprite they wanted to use or if the index was omitted they'd get a random (guaranteed to not be the same twice in a row) sprite from the list.

    For Addressables I tried to do something similar.
    I use labels for character and either label or address for category (haven't decided this yet) but I'm not sure how to do the ordered list part.

    The problem really is if the designer wants "happy" with index 2 I will look up all addresses with labels tagged "happy" and select 2 in that list. I'm not sure if Addressable can guarantee that that the order of the returned list of sprites will be the same each time?

    One idea was for the designer to either use same address for all sprites that belong to the "happy" category.
    The other to use a "happy" label on all sprites and then use a unique address and we have to skip numbered indexing.
     
  9. DavidUnity3d

    DavidUnity3d

    Unity Technologies

    Joined:
    Nov 17, 2016
    Posts:
    91
    I don't think we can guarantee that the list is the same each time the sprites are loaded, especially if the sprites are in different groups or packed separately. To be sure, I haven't confirmed this. If all your Happy sprites were in a single group and the groups BundledAssetGroupSchema was set to Pack Together I think you could be pretty confident the list would be the same. Data builds should be deterministic. When using multiple pack separately or different groups we can't guarantee load order.

    If you go that route but still want to refer to to sprites by their index you could build some kind of map/dictionary that maps the index to the unique key you're actually looking for.

    Hopefully something there will help you out. Let me know if I can be of further assistance.