We spent some time dealing with it.

    public class CustomAssemblyResolver : BaseAssemblyResolver, IDisposable
    {

        readonly IDictionary<string, AssemblyDefinition> cache;
        private readonly List<AssemblyDefinition> resolved = new
List<AssemblyDefinition>();


        public CustomAssemblyResolver()
        {
            cache = new Dictionary<string, AssemblyDefinition>();
        }

        public override AssemblyDefinition Resolve(AssemblyNameReference name)
        {
            if (name == null)
                throw new ArgumentNullException("name");

            AssemblyDefinition assembly;
            if (cache.TryGetValue(name.FullName, out assembly))
                return assembly;

            assembly = base.Resolve(name);
            cache[name.FullName] = assembly;
            resolved.Add(assembly);
            return assembly;
        }

        public override AssemblyDefinition Resolve(string name)
        {
            var assembly = base.Resolve(name);
            resolved.Add(assembly);
            return assembly;
        }

        public override AssemblyDefinition
Resolve(AssemblyNameReference name, ReaderParameters parameters)
        {
            var assembly = base.Resolve(name, parameters);
            resolved.Add(assembly);
            return assembly;
        }

        public override AssemblyDefinition Resolve(string fullName,
ReaderParameters parameters)
        {
            var assembly = base.Resolve(fullName, parameters);
            resolved.Add(assembly);
            return assembly;
        }


        protected void RegisterAssembly(AssemblyDefinition assembly)
        {
            resolved.Add(assembly);
            if (assembly == null)
                throw new ArgumentNullException("assembly");

            var name = assembly.Name.FullName;
            if (cache.ContainsKey(name))
                return;

            cache[name] = assembly;
        }

        public void Dispose()
        {
            resolved.ForEach(q => q.Dispose());
        }

        public string GetName()
        {
            return this.GetSearchDirectories()[0];
        }

        public IEnumerable<string> GetCachedAssemblies()
        {
            return resolved.Select(item => item.FullName);
        }

        public void SetNewSearchDirectoryTo(string path)
        {
            var dirs = GetSearchDirectories();
            foreach (var d in dirs)
            {
                RemoveSearchDirectory(d);
            }
            AddSearchDirectory(path);
        }
    }

On Wed, Jan 18, 2012 at 5:43 PM, Ken Beckett <[email protected]> wrote:
> I have an app that loads lots of .NET assemblies using Mono Cecil
> (actually a VS Solution with all Projects and all assembly
> references), and then repeats this process ad infinitum.
>
> There seems to be a terrible memory leak in the design of Mono Cecil
> when doing such a thing, in that the DefaultAssemblyResolver class
> keeps a private cache of all loaded AssemblyDefinition objects, and
> yet provides no means of ever purging this cache.  That sort of thing
> is always a nasty thing to do.  The simple addition of a PurgeCache()
> method would be nice - otherwise it's necessary to create a custom
> AssemblyResolver that derives from BaseAssemblyResolver to get around
> this problem.
>
> Which actually brings up another issue - the way that
> BaseAssemblyResolver lets you add/remove search directories is sort of
> nice... except that you never should actually remove a search
> directory due to deferred resolving that can occur, and therefore a
> single instance of this class should never be used to load assemblies
> for separate Projects or executables since they will generally need
> different search paths.  This problem therefore extends to the
> DefaultAssemblyResolver and GlobalAssemblyResolver.Instance - giving
> them not proper behavior for repeated loads of different groups of
> assemblies using different search paths.
>
> In summary, Mono Cecil appears to be designed to do a one-time load of
> a group of related assemblies that you never unload from memory.  It
> does not appear to handle (as-is) repeated loads of different groups
> of assemblies with different search paths and proper unloading.  This
> would seem to require a custom AssemblyResolver with different
> instances (and search paths) used for each related group that is
> loaded, and any AssemblyDefinition caching must be done at a higher/
> separate level in order to work properly.
>
> --
> --
> mono-cecil



-- 
Le doute n'est pas une condition agréable, mais la certitude est absurde.

-- 
--
mono-cecil

Reply via email to