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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more..
    Dismiss Notice
  3. Dismiss Notice

Bug LoadFromStreamAsync seems to keep running after stopping Player in Editor

Discussion in 'Asset Bundles' started by ArjoNagelhout, Jun 15, 2023.

  1. ArjoNagelhout

    ArjoNagelhout

    Joined:
    Feb 10, 2019
    Posts:
    4
    I'm loading the asset bundle in a coroutine from a ZipStream, which I copy to a MemoryStream. Then I use LoadFromStreamAsync to load the asset bundle. See:

    Code (CSharp):
    1. using (MemoryStream memoryStream = new MemoryStream())
    2. {
    3.     zipStream.CopyTo(memoryStream);
    4.     request = AssetBundle.LoadFromStreamAsync(memoryStream);
    5.     while (!request.isDone) { yield return null; }
    6. }
    7.  
    8. AssetBundle result = request.assetBundle;
    I want to keep the AssetBundle loaded in memory (i.e. store it in an AssetBundle variable somewhere), but the MemoryStream gets disposed after the request is done.

    Now I see this piece in the documentation:

    > Do not dispose the Stream object while loading the AssetBundle or any assets from the bundle. Its lifetime should be longer than the AssetBundle. This means you dispose the Stream object after calling AssetBundle.Unload.​

    Taken from https://docs.unity3d.com/ScriptReference/AssetBundle.LoadFromStreamAsync.html

    Why is that? Am I doing something that shouldn't be done / done in a different way? Should I just keep the MemoryStream around? That doesn't feel right.

    I'm asking because when stopping this coroutine in OnApplicationQuit, it still loads the AssetBundle in memory and gives the following error when running the coroutine again on the next time pressing Play in the Editor:

    > The AssetBundle 'IO.Stream' can't be loaded because another AssetBundle with the same files is already loaded.

    Thanks in advance for any advice :) Normally I just read source code / existing questions, but this I couldn't find that much on.
     
  2. ArjoNagelhout

    ArjoNagelhout

    Joined:
    Feb 10, 2019
    Posts:
    4
  3. ArjoNagelhout

    ArjoNagelhout

    Joined:
    Feb 10, 2019
    Posts:
    4
    If the AssetBundle.LoadFromStreamAsync operation has completed in between stopping and pressing Play again, AssetBundle.UnloadAllAssetBundles does work to clean up the loaded AssetBundle.

    However, if the AssetBundle.LoadFromStreamAsync operation is still running after pressing Play, the error [0] will persist.

    [0] The AssetBundle 'IO.Stream' can't be loaded because another AssetBundle with the same files is already loaded.
     
  4. AndrewSkow

    AndrewSkow

    Unity Technologies

    Joined:
    Nov 17, 2020
    Posts:
    78
    Hi ArjoNagelhout

    Regarding your original questions about MemoryStream usage - yes you need to keep that around as long as the AssetBundle is loaded. That is because Loading an AssetBundle does not fully load the entire contents immediately. Instead Unity will attempt to save memory by only bringing sections of the file into memory on-demand. So as Assets are loaded it can end up reading the underlying file in a random access sort of way.

    Normally this is a file on disk, but the MemoryStream support is there to use an in-memory image of the AssetBundle as an alternative. Your usage of that to hold the on-demand decompressed version makes sense. Unity also sometimes creates in-memory versions of the AssetBundle contents, we've improved the documentation about that recently in https://docs.unity3d.com/2023.2/Documentation/Manual/AssetBundles-Cache.html.

    Perhaps you can have a small wrapper class that combines the MemoryStream reference and AssetBundle object, so you can unload and dispose them together when you are done using them.