The following situation turned out ...

1) Create a domain in the application.
2) Load it into it via DoCallBack assembly Assembly.Load(...)
3) From the main domain we get the assemblies previously created and, for example, display their names.
4) We look at what assemblies are in the main domain, and more specifically, there appeared this assembly that we uploaded to another domain.

That is, loading the assembly to another domain, if you use the GetAssemblies method, the loaded assemblies appear in the main domain, and they are not just transferred there, they are copied - they can be used in both domains.

If you loop the process and watch the memory, you can see that it grows, which means the assemblies are loaded with a new one into memory each time.

The main question is why? How to get rid of the transfer of the assembly in the main domain? There is not even a matter of memory, but the fact that the main domain holds the reference for the assembly and does not allow it to be deleted, for example. And somehow it is necessary to pull out an infa.

 class Program { static void Main ( string [ ] args ) { var appDomain = AppDomain.CreateDomain("TestDomain"); appDomain.DoCallBack(LoadModule); var assembly = appDomain.GetAssemblies().Single( t => t.GetName().Name == "TestModule" ); foreach ( var assembly1 in AppDomain.CurrentDomain.GetAssemblies() ) { Console.WriteLine( assembly1.FullName ); } } private static void LoadModule() { Assembly.Load( "TestModule" ); } } 
  • one
    Show the code. My guess is that in point 3 you transfer the Assembly objects from the additional domain to the main one, which naturally leads to the loading of the assemblies into the main domain (and not necessarily those that were loaded into the additional one). - PetSerAl
  • @PetSerAl, I don’t give anything, one GetAssemblyes call will GetAssemblyes , I wrote. - anweledig
  • Hm You call appDomain.GetAssemblies() , and for each of them call GetName() . I think it loads your builds in the main domain. - VladD

1 answer 1

There are two ways to pass an object across the application domain boundary:

  1. Through the proxy. For objects inheriting from System.MarshalByRefObject . In this case, all method calls on the proxy object are automatically redirected to the application domain to which the source object belongs.
  2. Through binary serialization. For objects that support it. This creates a copy of the object that is no longer associated with the original object.

In this case, the System.AppDomain class inherits from System.MarshalByRefObject , while the System.Reflection.Assembly class does not. That is, the call of appDomain.GetAssemblies() in your code will be redirected to an additional application domain, after which the result of its work ( Assembly[] ) will need to be transferred to the main application domain: serialized into an additional domain and deserialized in the main domain. This transfer of Assembly objects to the main application domain results in loading assemblies into it.

To avoid loading assemblies into the primary domain, do not pass objects into it that you need to load the assembly to deserialize. Like the System.Reflection.Assembly object representing the assembly, the System.Type object representing any type from the assembly, an instance of any type from the assembly.

For example, assembly names can be retrieved in an additional application domain, and only lines in the main domain can be transferred:

 using System; using System.Linq; using System.Reflection; class Program { static void Main ( string [ ] args ) { var appDomain = AppDomain.CreateDomain("TestDomain"); appDomain.DoCallBack(LoadModule); var worker = (Worker)appDomain.CreateInstanceAndUnwrap(typeof(Worker).Assembly.FullName, typeof(Worker).FullName); foreach ( var assemblyFullName1 in worker.GetAssembliesFullName() ) { Console.WriteLine( assemblyFullName1 ); } Console.WriteLine(); foreach ( var assembly1 in AppDomain.CurrentDomain.GetAssemblies() ) { Console.WriteLine( assembly1.FullName ); } } private static void LoadModule() { Assembly.Load( "TestModule" ); } } class Worker : MarshalByRefObject { public string[] GetAssembliesFullName() { return AppDomain.CurrentDomain.GetAssemblies().Select(a => a.FullName).ToArray(); } }