Problem We are publishing a lot of microservices on one machine, i.e.: 30 instances and every one use 150 – 300 mb. A lot of microservices use the same libraries, but load it independent.
Question Can the CLR load assembly once and share it with other domains for reduce memory usage?
Investigation and experiment When I investigated this problem through ProcessExplorer, I've seen there are 2 Application domain for every w3wp process. One of them is used to load assemblies from GAC and another to load assemblies from the application folder.
When I put common assemblies in GAC. It increase Shareable, Shared WS and reduce Private WS for all processes. But Working set without changes.
Open VMMap and have a look at memory structure of w3wp process.
- 61 out of 158 Mb – Image (loaded assembly)
- 40 out of 158 Mb – Page files (memory associated with process)
The simplest way to reduce memory usage: it's combine multiple sites into one application domain. Startup time for every single site will be reduce.
If there are a lot of assemblies with strong name you can put them in GAC. It's make their domain neutral assembly for w3wp process. Such assemblies are domain neutral if and only if it is in GAC, and all the assemblies in its transitive binding closure are all in GAC. (see also blogs.msdn)
Domain neutral assembly pros and cons:
- (pros) domain neutral assembly is an assembly that lives across multiple appdomains
- (pros) domain neutral assemblies will be jitted only once
- (pros) the jitted code, as well as various runtime data structures like MethodTables, MethodDescs, will be shared across appdomains.
- (cons) you can not update strongly named assemblies once it is loaded in domain, so you should recycle (reload) application pool.
Some words about strong named assemblies and GAC.
If your assemblies have strong names, make sure to place them in the global assembly cache (GAC).
Otherwise, loading the assembly requires touching almost every page to verify its digital signature.
Verification of strong names when the assembly is not placed in the GAC will also diminish any performance gains from NGen.
(see also: Pro .NET Performance: Optimize Your C# Applications. Page 289)