.Net Application Memory Management - c#

Could be a very naive question, but was wondering how this stuff works: Lets assume that we have 10 projects in Visual Studio, and 5 of them have references to an external DLL (say Ext.dll), using a relative path.
Now when my application is deployed an running on client machine, would Ext.dll get loaded 5 times in memory? Or would it just get loaded once and gets used by other referencing projects?

Assembly will be loaded only once in memory.
CLR first check if assembly already loaded in current AppDomain, if not than assembly gets loaded under AppDomain otherwise symbols are resolved from the already loaded assembly.
Ofcourse unless you are manually creating another AppDomain which has its own set of assemblies.
Moreover, assembly with same version cannot be loaded in memory at
same time. CLR doesn't allow that. But you can have different versions
of same assembly to be loaded in memory and that too in case
assemblies are strongly signed. But in your case version is same so CLR won't load same assembly twice anyhow.
If you want to check at certain interval time that what assemblies are loaded in a memory, you can use this piece of code to get all loaded assemblies:
var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();

Clr load assembly in memory just once.
Note :for each instance of application Clr load assembly again.
You can read Clr via c#.In chapter one you can learn many of these Concepts.

Related

How can I kill a dll loaded with reflection [duplicate]

I would like to know how to unload an assembly that is loaded into the main AppDomain.
I have the following code:
var assembly = Assembly.LoadFrom( FilePathHere );
I need/want to be able to unload this assembly when I am done.
Thanks for your help.
For .net versions core 3.0 and later:
You can now unload assemblies. Note that appdomains are no longer available in .net core. Instead, you can create one or more AssemblyLoadContext, load your assemblies via that context, then unload that context. See AssemblyLoadContext, or this tutorial that simulates loading a plugin then unloading it.
For .net versions before .net core 3, including netframework 4 and lower
You can not unload an assembly from an appdomain. You can destroy appdomains, but once an assembly is loaded into an appdomain, it's there for the life of the appdomain.
See Jason Zander's explanation of Why isn't there an Assembly.Unload method?
If you are using 3.5, you can use the AddIn Framework to make it easier to manage/call into different AppDomains (which you can unload, unloading all the assemblies). If you are using versions before that, you need to create a new appdomain yourself to unload it.
I also know this is very old, but may help someone who is having this issue!
Here is one way I have found to do it!
instead of using:
var assembly = Assembly.LoadFrom( FilePathHere );
use this:
var assembly = Assembly.Load( File.ReadAllBytes(FilePathHere));
This actually loads the "Contents" of the assembly file, instead of the file itself. Which means there is NOT a file lock placed on the assembly file! So now it can be copied over, deleted or upgraded without closing your application or trying to use a separate AppDomain or Marshaling!
PROS: Very Simple to fix with a 1 Liner of code!
CONS: Cannot use AppDomain, Assembly.Location or Assembly.CodeBase.
Now you just need to destroy any instances created on the assembly.
For example:
assembly = null;
You can't unload an assembly without unloading the whole AppDomain. Here's why:
You are running that code in the app domain. That means there are potentially call sites and call stacks with addresses in them that are expecting to keep working.
Say you did manage to track all handles and references to already running code by an assembly. Assuming you didn't ngen the code, once you successfully freed up the assembly, you have only freed up the metadata and IL. The JIT'd code is still allocated in the app domain loader heap (JIT'd methods are allocated sequentially in a buffer in the order in which they are called).
The final issue relates to code which has been loaded shared, otherwise more formally know as "domain neutral" (check out /shared on the ngen tool). In this mode, the code for an assembly is generated to be executed from any app domain (nothing hard wired).
It is recommended that you design your application around the application domain boundary naturally, where unload is fully supported.
You should load your temporary assemblies in another AppDomain and when not in use then you can unload that AppDomain. It's safe and fast.
If you want to have temporary code which can be unloaded afterwards, depending on your needs the DynamicMethod class might do what you want. That doesn't give you classes, though.
Here is a GOOD example how to compile and run dll during run time and then unload all resources:
http://www.west-wind.com/presentations/dynamicCode/DynamicCode.htm
I know its old but might help someone. You can load the file from stream and release it. It worked for me. I found the solution HERE.
Hope it helps.
As an alternative, if the assembly was just loaded in the first place, to check information of the assembly like the publicKey, the better way would be to not load it,and rather check the information by loading just the AssemblyName at first:
AssemblyName an = AssemblyName.GetAssemblyName ("myfile.exe");
byte[] publicKey = an.GetPublicKey();
CultureInfo culture = an.CultureInfo;
Version version = an.Version;
EDIT
If you need to reflect the types in the assembly without getting the assembly in to your app domain, you can use the Assembly.ReflectionOnlyLoadFrom method.
this will allow you to look at they types in the assembly but not allow you to instantiate them, and will also not load the assembly in to the AppDomain.
Look at this example as exlanation
public void AssemblyLoadTest(string assemblyToLoad)
{
var initialAppDomainAssemblyCount = AppDomain.CurrentDomain.GetAssemblies().Count(); //4
Assembly.ReflectionOnlyLoad(assemblyToLoad);
var reflectionOnlyAppDomainAssemblyCount = AppDomain.CurrentDomain.GetAssemblies().Count(); //4
//Shows that assembly is NOT loaded in to AppDomain with Assembly.ReflectionOnlyLoad
Assert.AreEqual(initialAppDomainAssemblyCount, reflectionOnlyAppDomainAssemblyCount); // 4 == 4
Assembly.Load(assemblyToLoad);
var loadAppDomainAssemblyCount = AppDomain.CurrentDomain.GetAssemblies().Count(); //5
//Shows that assembly is loaded in to AppDomain with Assembly.Load
Assert.AreNotEqual(initialAppDomainAssemblyCount, loadAppDomainAssemblyCount); // 4 != 5
}

Dynamically loading multiple versions of an assembly

I am writing a test app to perform some regression tests. The idea is to be able to run test over multiple versions of a library. My goal is to load the dlls up in a Dictionary where the key is the version string (such as "3.0.0.0") and the value is the Assembly instance. I am able to dynamically load one assembly and call a method on it, but when I try to load a second one, I get the following exception:
The located assembly's manifest definition does not match the assembly reference.
I am loading the assemblies with the following line:
asm = Assembly.LoadFrom(lib, hash, System.Configuration.Assemblies.AssemblyHashAlgorithm.MD5);
'lib' is the complete filename and path of the dll.
'hash' is the md5 sum of the dll.
I looks like even though I am telling Windows "use this dll", it looks at the name and says "I already have that one" and uses the previously loaded one and since the hash doesn't match, it fails. Originally, the dlls being loaded did not have an Assembly Version set, so I set it on 4 different versions, but it still threw the same exception.
What is the fix for this?
Jordon
You cannot load more than one version of the same assembly into single AppDomain. Also once loaded, assembly cannot be unloaded from AppDomain (with exception of dynamically created transient assemblies in .NET 4), but it is possible to unload whole AppDomain (which unloads all assemblies, that were loaded in it). Therefore you must load each version of your assembly into separate (newly created) AppDomain. Also be very careful to NOT pass any reference to loaded assembly between individual AppDomains (and especially to main AppDomain, where your testing app resides), because otherwise .NET will try to load assembly into every AppDomain, where reference to this assembly appears and you will end up with the same error again.
You'll need to the assemblies into separate AppDomains.

Delay loading in c#?

Is there such a thing as delay loading a dll in C#?
I know this is possible to do in C++, but what about managed code?
.NET does that automatically, everything is loaded on demand by default.
This article explains in detail how it works in .NET. Summary of key points:
There are a number of different ways that assemblies are loaded in
.NET. When you create a typical project, assemblies usually come from:
The Assembly reference list of the top level 'executable' project
The Assembly references of referenced projects
Dynamically loaded assemblies, using runtime loading via AppDomain or Reflection loading
and
.NET automatically loads mscorlib (most of the System namespace) as part of the .NET runtime hosting process that hoists up
the .NET runtime in EXE apps, or some other kind of runtime hosting
environment (runtime hosting in servers like IIS, SQL Server or COM
Interop).
and
Dependent Assembly References are not pre-loaded when an application starts (by default)
Dependent Assemblies that are not referenced by executing code are never loaded
Dependent Assemblies are just in time loaded when first referenced in code
Once Assemblies are loaded they can never be unloaded, unless the AppDomain that hosts them is unloaded.
Yes it is. You don't include the DLL as a reference in your project and where you want to load/use it, you call the Assembly.LoadFile method.
This blog post does a pretty good job with code to describe how to do it.

help with dll reference count in a circular reference situation in c# 4.0

Iam maintaining a large code base I have inherited (ported from vb6 to C#.net 1.1, then to .net 2.0/c# and so on). I have this scenario
My main project references two DLLs - DLL-A and DLL-B
DLL-B references DLL-A. Both dll's and my main project are in 3 separate namespaces.
1) Are 2 copies of DLL-A being loaded in memory ? (dll ref count)
2) How do I find out how many copies of a .net dll is loaded in mem ? (which tool is normally used)
thank you
No, DLL-A will only be loaded once. It's just like everything references mscorlib - but only one copy of that is loaded in.
Unless you're doing something funky (using multiple AppDomains, loading assemblies with reflection, hosting multiple CLRs side-by-side) you'll only get one copy of an assembly reference.
1) No. When the application or library (DLL-B) uses a type from DLL-A, it will be loaded into memory. When it's used later by the other source, the same copy will be used.
2) Only one copy of the assembly will get loaded into the AppDomain of your process. In a normal application, this means a single copy will get loaded of each assembly (ie: dll) you use.
There is no "reference counting" happening here.

Why are some .Net assemblies not available via an AppDomain's GetAssemblies() method?

I have a little bit of code that loops through the types currently loaded into an AppDomain that runs in an ASP.NET application. Here's how I get the assemblies:
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
When the application first starts up there is no problem and all the types I expect are present. But when I update the Web.config or kill the w3p.exe process (or the process gets recycled for whatever reason) only some of the types I'm expecting are available. When I step through with a debugger I notice that certain assemblies from the private search path (the bin directory of my application) haven't been loaded. I was under the assumption that all assemblies were loaded at application start and restart whether or not they were immediately required. But in the case of restarting this doesn't seem to be happening unless those assembly files have been updated.
What I require is to collect type information at start-up for use later. But since during a restart the types aren't available it reeks havoc later on when the type information needs to be used. So with that in mind how can I solve or work around this deficiency?
Assemblies are loaded on demand, so it could be that you did not used any type contained in these assemblies yet.
You can use
AssemblyName[] assemblies = Assembly.GetCallingAssembly().GetReferencedAssemblies();
This way, you get all assemblies that are referenced from the assembly from which you are calling these method.
As a part of startup, can you explicitly load the assemblies you care about?
You would have to know ahead of time which assemblies you would need.
Scanning the filesystem to find out which assemblies have been shipped along with your app may be a useful idea, but it won't help for GAC loaded assemblies...

Categories

Resources