Search Unity

Addressable and Too many open files

Discussion in 'Addressables' started by araki_yuta, Jan 23, 2020.

  1. araki_yuta

    araki_yuta

    Joined:
    Jan 21, 2020
    Posts:
    14
    Hello there,

    I'm currently in process of evaluating AAS for use with our current and forthcoming project. While trying to evaluate how AAS behave with 1000+ asset DependencyDownload, it started to fail on me.

    As I was digging around, it looks to me that while DependencyDownload is doing its thing, its not releasing the lock files until all the assetbundles where downloaded. After about 900 files or so, OS starts to tell me too many open files. lsof command sure listed quite many __lock files. Is this by design?
     
    Last edited: Jan 24, 2020
  2. araki_yuta

    araki_yuta

    Joined:
    Jan 21, 2020
    Posts:
    14
    So after much tinkering, I was able to avoid this situation by modifying
    DownloadDependenciesAsync
    implementation.
    After all, seems like DownloadDependencies doesn't let go of locks for assetbundles being downloaded and trying to download thousands of files causes too many file open error. I'm not sure how this plays out on mobile devices but it sure fails on macOS build.

    By modifying
    DownloadDependenciesAsync
    to take a callback for
    LoadAssetsAsync
    performed inside and unloading asset bundle after it's done downloading, the problem is gone.

    Not sure if this is right way of doing it but I couldn't find anyway around this.

    I changed:
    Code (CSharp):
    1.  public AsyncOperationHandle DownloadDependenciesAsync(object key, bool autoReleaseHandle = false)
    2.         {
    3.             if (ShouldChainRequest)
    4.                 return DownloadDependenciesAsyncWithChain(ChainOperation, key, autoReleaseHandle);
    5.  
    6.             IList<IResourceLocation> locations;
    7.             if (!GetResourceLocations(key, typeof(object), out locations))
    8.             {
    9.                 var handle = ResourceManager.CreateCompletedOperation<IList<IAssetBundleResource>>(null,
    10.                     new InvalidKeyException(key, typeof(object)).Message);
    11.                 if (autoReleaseHandle)
    12.                     handle.Completed += op => Release(op);
    13.                 return handle;
    14.             }
    15.             else
    16.             {
    17.                 var locHash = new HashSet<IResourceLocation>();
    18.                 foreach (var loc in locations)
    19.                 {
    20.                     if (loc.HasDependencies)
    21.                     {
    22.                         foreach (var dep in loc.Dependencies)
    23.                             locHash.Add(dep);
    24.                     }
    25.                 }
    26.                 var handle = LoadAssetsAsync<IAssetBundleResource>(new List<IResourceLocation>(locHash), null);
    27.                 if (autoReleaseHandle)
    28.                     handle.Completed += op => Release(op);
    29.                 return handle;
    30.             }
    31.         }
    32.  
    to following
    Code (CSharp):
    1. public AsyncOperationHandle DownloadDependenciesAsync(object key, bool autoReleaseHandle = false, Action<IAssetBundleResource> callback = null)
    2.         {
    3.             if (ShouldChainRequest)
    4.                 return DownloadDependenciesAsyncWithChain(ChainOperation, key, autoReleaseHandle);
    5.  
    6.             IList<IResourceLocation> locations;
    7.             if (!GetResourceLocations(key, typeof(object), out locations))
    8.             {
    9.                 var handle = ResourceManager.CreateCompletedOperation<IList<IAssetBundleResource>>(null,
    10.                     new InvalidKeyException(key, typeof(object)).Message);
    11.                 if (autoReleaseHandle)
    12.                     handle.Completed += op => Release(op);
    13.                 return handle;
    14.             }
    15.             else
    16.             {
    17.                 var locHash = new HashSet<IResourceLocation>();
    18.                 foreach (var loc in locations)
    19.                 {
    20.                     if (loc.HasDependencies)
    21.                     {
    22.                         foreach (var dep in loc.Dependencies)
    23.                             locHash.Add(dep);
    24.                     }
    25.                 }
    26.                 var handle = LoadAssetsAsync<IAssetBundleResource>(new List<IResourceLocation>(locHash), callback);
    27.                 if (autoReleaseHandle)
    28.                     handle.Completed += op => Release(op);
    29.                 return handle;
    30.             }
    31.         }
    and pass
    Code (CSharp):
    1. private void UnloadAssetBundles(IAssetBundleResource assetBundleResource)
    2.         {
    3.             if (assetBundleResource == null)
    4.             {
    5.                 return;
    6.             }
    7.  
    8.             var assetBundle = assetBundleResource.GetAssetBundle();
    9.             if (assetBundle != null)
    10.             {
    11.                 assetBundle.Unload(true);
    12.             }
    13.         }
    as callback.
     
    Petr777, Prince_of_Persia and Jaimi like this.