Addressable and Too many open files

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?

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:

 public AsyncOperationHandle DownloadDependenciesAsync(object key, bool autoReleaseHandle = false)
        {
            if (ShouldChainRequest)
                return DownloadDependenciesAsyncWithChain(ChainOperation, key, autoReleaseHandle);

            IList<IResourceLocation> locations;
            if (!GetResourceLocations(key, typeof(object), out locations))
            {
                var handle = ResourceManager.CreateCompletedOperation<IList<IAssetBundleResource>>(null,
                    new InvalidKeyException(key, typeof(object)).Message);
                if (autoReleaseHandle)
                    handle.Completed += op => Release(op);
                return handle;
            }
            else
            {
                var locHash = new HashSet<IResourceLocation>();
                foreach (var loc in locations)
                {
                    if (loc.HasDependencies)
                    {
                        foreach (var dep in loc.Dependencies)
                            locHash.Add(dep);
                    }
                }
                var handle = LoadAssetsAsync<IAssetBundleResource>(new List<IResourceLocation>(locHash), null);
                if (autoReleaseHandle)
                    handle.Completed += op => Release(op);
                return handle;
            }
        }

to following

public AsyncOperationHandle DownloadDependenciesAsync(object key, bool autoReleaseHandle = false, Action<IAssetBundleResource> callback = null)
        {
            if (ShouldChainRequest)
                return DownloadDependenciesAsyncWithChain(ChainOperation, key, autoReleaseHandle);

            IList<IResourceLocation> locations;
            if (!GetResourceLocations(key, typeof(object), out locations))
            {
                var handle = ResourceManager.CreateCompletedOperation<IList<IAssetBundleResource>>(null,
                    new InvalidKeyException(key, typeof(object)).Message);
                if (autoReleaseHandle)
                    handle.Completed += op => Release(op);
                return handle;
            }
            else
            {
                var locHash = new HashSet<IResourceLocation>();
                foreach (var loc in locations)
                {
                    if (loc.HasDependencies)
                    {
                        foreach (var dep in loc.Dependencies)
                            locHash.Add(dep);
                    }
                }
                var handle = LoadAssetsAsync<IAssetBundleResource>(new List<IResourceLocation>(locHash), callback);
                if (autoReleaseHandle)
                    handle.Completed += op => Release(op);
                return handle;
            }
        }

and pass

private void UnloadAssetBundles(IAssetBundleResource assetBundleResource)
        {
            if (assetBundleResource == null)
            {
                return;
            }

            var assetBundle = assetBundleResource.GetAssetBundle();
            if (assetBundle != null)
            {
                assetBundle.Unload(true);
            }
        }

as callback.

3 Likes