Does project load DLL multiple times?

  • Thread starter Thread starter Brett Romero
  • Start date Start date
B

Brett Romero

If my UI app uses three DLLs and two of those DLLs reference something
named utilities.dll, does the UI app load utilities.dll twice or does
the compiler recognize what is going on and load utilities.dll just
once?

Thanks,
Brett
 
Also, if utilities.dll is using the Forms namespace because it has
classes that use forms, is there any waste of memory in the middle teir
DLLs if they are not loading forms? In other words, if I reference
the Forms namespace but never create a form, does the Forms namespace
still use memory?

If memory is used by the Forms namespace in this scenario, is it enough
to be noticeable? Just looking for details of how this works.

Thanks,
Brett
 
Brett,

See inline:
If my UI app uses three DLLs and two of those DLLs reference something
named utilities.dll, does the UI app load utilities.dll twice or does
the compiler recognize what is going on and load utilities.dll just
once?

The app will load utilities.dll for each app domain that it is used in.
For most programs, there is only ever one app domain, and it will be loaded
once for that app domain. In ASP.NET, however, you can have multiple app
domains, and load the DLL multiple times in that process.

Hope this helps.
 
Brett,

You can't use a namespace. You have to use types that are in a
namespace.

Also, one might ask, if you are not using classes exposed by a certain
assembly, why do you have a reference to it?
 
The app will load utilities.dll for each app domain that it is used in.
For most programs, there is only ever one app domain, and it will be
loaded once for that app domain. In ASP.NET, however, you can have
multiple app domains, and load the DLL multiple times in that process.

Are you sure about this? This is not standard Windows behavior with DLLs:
If a single DLL is referenced multiple times y multiple processes, the DLL
executable code itself is loaded only once, the memory the code resides on
is mapped (read-only, of course) into each process that uses the DLL. The
working memory that the DLL uses _does_ get allocated once per user process
so that processes don't interfere with each other, but the bottom line is
that the actual executable code for each unique DLL is loaded only once and
subsequent "loads" do not take any additional memory for the DLL code. See
http://msdn.microsoft.com/msdnmag/issues/02/03/Loader/ for a more in-depth
description of this.

Does .NET override this Windows behavior?
 
Gabriel,

Sorry, I should be more specific. For each app domain that the assembly
is loaded into, in the same process, the code pages will be shared among all
app domains in that process.

The data pages are duplicated across the app domains.

Across processes though, there is no sharing, each process has a
separate code page loaded.

I recall hearing that Vista will have work done to optimize this, since
a good part of the OS will be using managed assemblies now (for WPF, WW, and
WFC apps), but I don't recall the specifics.

Here is some more information on app domains and assemblies:

http://msdn.microsoft.com/library/d...de/html/cpconapplicationdomainsassemblies.asp
 
So then... If I have a big class library that I use on every project, and
that library is 1 MB in size (1 MB of executable code), then every app
domain that references that library will increase its memory footprint by 1
MB (plus the heap-memory, etc...) every time I run an application that uses
the class library?

What about the .NET framework itself? If I run two applications that use
the .NET framework, will the framework be completely loaded twice?

If this is true, then everyone would be well advised to keep general-purpose
class libraries as small as possible...
 
Gabriel,

No, only the data pages in the library will be loaded each time. The
data pages (filled with things such as constants, for example) will be
duplicated across EACH app domain.

As for the framework itself, the CLR is loaded into the process space of
EACH process it is in. If you have multiple app domains that are running in
the same process, then the CLR is loaded once for the process. However, if
you have two apps in two separate processes, then the CLR is loaded twice.
 
As for the framework itself, the CLR is loaded into the process space
of EACH process it is in. If you have multiple app domains that are
running in the same process, then the CLR is loaded once for the process.
However, if you have two apps in two separate processes, then the CLR is
loaded twice.

Can you put thi in terms of RAM :-)? I think we are talking about the sme
idea but maybe stating the same thing in different terms. If two separate
processes use the same DLL, then the DLL executable code is _not_ loaded
twice into RAM, the already-loaded executable code only exists in RAM once,
the code page is just re-mapped from the one instance in memory. Am I right
so far?

Now the data page, the memory area that contains the memory that the DLL is
modifying, _does_ get duplicated for each app domain...

In other words, given an executable code of a DLL that is 500K and the data
memory used by the DLL is 64K: If three app domains use the DLL/class
library, 500K + 64K + 64K + 64K of memory will be used. Is this correct?
 
Gabriel,
Can you put thi in terms of RAM :-)?

No, not really, since I don't know what the breakdown of the code pages
vs data pages for any given assembly are. It's dependent on what is in the
assembly.
I think we are talking about the sme idea but maybe stating the same thing
in different terms. If two separate processes use the same DLL, then the
DLL executable code is _not_ loaded twice into RAM, the already-loaded
executable code only exists in RAM once, the code page is just re-mapped
from the one instance in memory. Am I right so far?

No, it does exist in RAM twice, once for each process. For a single
process, with multiple app domains, the code page will only be loaded once,
not once for each app domain. The data pages, however, will be loaded once
for each app domain.
Now the data page, the memory area that contains the memory that the DLL
is modifying, _does_ get duplicated for each app domain...
Yes.

In other words, given an executable code of a DLL that is 500K and the
data memory used by the DLL is 64K: If three app domains use the DLL/class
library, 500K + 64K + 64K + 64K of memory will be used. Is this correct?

Yes, assuming the three app domains are in the same process, not
separate processes.
 
Say the library A.dll file references System.Windows.Forms.dll and then
my EXE webform project also references System.Windows.Forms. The EXE
calls objects in the Forms namespace, namely to create its forms. No
calls have been made into the Forms namespace of A.dll. Assuming
System.Forms.Windows.dll is 500k loaded in memory and the data pages
are 64k each, does it currently looks like:

500k ("both" EXE and A.dll have load System.Forms.Windows.dll) and not
500k + 500k = 1000k
+ 64k (only the EXE has called into the Forms namespace)
-------
564k total

Good so far?

Now, the point behind this is: Would it be worth me removing the
System.Windows.Forms namespace from A.dll and putting it into a UI.dll?
For any non forms libraries that call A.dll, they will "have to" load
the Forms namespace right, since A.dll file references
System.Windows.Forms.dll? Since those libraries will never call into
the Forms namespace, loading the Forms namespace is a waste of memory.

500k - System.Windows.Forms.dll (A.dll is loaded by B.dll, non form
library)
+ 50k - A.dll (references Forms namespace)
+ 50k - B.dll
----------
600k + data pages

Isn't this a waste of 500k memory?

On the other hand, if those same libraries are also going to be file
referenced by a winform app, what difference does it make if I leave
the Forms namespace in A.dll vs. putting it into UI.dll. The Forms
namespace is already loaded by the winform app and a data page is
created when a call is made from an assembly.

In this version, A.dll no longer references the Forms namespace. Forms
namespace has been moved to UI.dll.

500k - System.Windows.Forms.dll
+ 400k - winform.dll (loads A.dll, UI.dll and references
System.Windows.Forms.dll)
+ 50k - A.dll (loads B.dll)
+ 50k - B.dll
+ 50k - UI.dll (Didn't this just waste 50k memory. Forms namespace
could have stayed in A.dll)
 
Brett,

See inline.
Say the library A.dll file references System.Windows.Forms.dll and then
my EXE webform project also references System.Windows.Forms. The EXE
calls objects in the Forms namespace, namely to create its forms. No
calls have been made into the Forms namespace of A.dll.

There is no such thing as the "forms namespace of A.dll". I think that
what you are trying to say is that there are no calls made from types in
A.dll to System.Windows.Forms.dll, while there are calls from the EXE into
type in System.Windows.Forms.dll.
Assuming
System.Forms.Windows.dll is 500k loaded in memory and the data pages
are 64k each, does it currently looks like:

500k ("both" EXE and A.dll have load System.Forms.Windows.dll) and not
500k + 500k = 1000k
+ 64k (only the EXE has called into the Forms namespace)

No, if System.Windows.Forms.dll is a total of 500k, and types are used
from System.Windows.Forms.dll, then 500k is used. The total of 500 includes
the code and the data page. If the data page is 64k of the 500k, and there
is more than one app domain, (say two), then you have an additional 64k
being used by each app domain for the data page for the dll.
Good so far?

Now, the point behind this is: Would it be worth me removing the
System.Windows.Forms namespace from A.dll and putting it into a UI.dll?
For any non forms libraries that call A.dll, they will "have to" load
the Forms namespace right, since A.dll file references
System.Windows.Forms.dll? Since those libraries will never call into
the Forms namespace, loading the Forms namespace is a waste of memory.

Well, not necessarily. If types that are exposed by
System.Windows.Forms.dll are never called by the types in A.dll, then
System.Windows.Forms.dll is not loaded, unless some other type in another
assembly called into it, causing it to load.

You can set a reference to as many assemblies as you wish, but if you do
not access the types in that assembly in any way, then the loader will not
go through the trouble of loading the assembly.
500k - System.Windows.Forms.dll (A.dll is loaded by B.dll, non form
library)
+ 50k - A.dll (references Forms namespace)
+ 50k - B.dll

No, the total is 600k. Remember, your initial example is 500k for the
code and the data pages.
Isn't this a waste of 500k memory?

Well, it depends on what you mean by waste. In the scheme of things
today, I would say that 500k is not. However, System.Windows.Forms.dll is a
bit bigger than that (5MB+), and I would say THAT is a waste. Of course, in
the words of Depeche Mode, everything counts in large amounts, meaning, if
you load enough small dlls, you could have a problem.
On the other hand, if those same libraries are also going to be file
referenced by a winform app, what difference does it make if I leave
the Forms namespace in A.dll vs. putting it into UI.dll. The Forms
namespace is already loaded by the winform app and a data page is
created when a call is made from an assembly.

If System.Windows.Forms.dll is going to be referenced by another
assembly, then it doesn't matter.

The situation you want to avoid is exposing a function which is going to
be used often in a library where the rest of the library is not used.

A good example of this is the HttpContext class. It resides in
System.Web.dll. Usually, people want to find out if their app is running in
ASP.NET or not. So, you can go to HttpContext and access the static Current
property to see if there is an HttpContext. If it returns null, then you
are not running in ASP.NET.

Now, the thing is, to use this, if you are not in a web application (and
subsequently, would not use any of the functionality), then you end up
loading System.Web.dll JUST for determining if you are in ASP.NET, and you
end up loading 4MB+ into your app process/app domain space. That's a bit of
a waste, and what you want to avoid.

So, it's not really the reference to System.Windows.Forms.dll you have
to worry about, but rather, it is the other code that doesn't access it, and
the usage pattern. If you have to use System.Windows.Forms.dll, there is no
way around it, and just creating a reference to it is not going to impact in
any great way.

What you really have to look out for is exposing methods/types which are
used frequently, and then exposing a large code base in the same assembly
that is not used. If these types are not used too often, they are
participating in the code and data pages for the assembly and causing a
waste. They would be better off in another assembly.
 
Thanks Nicholas. What are some references that discuss this particular
topic?

Brett
 
Brett,

There is documentation on the MSDN site. You can search for app domain,
process, code page, data page, etc, etc, and you should find it.

As for how things get loaded, you can see how the CLR loads assemblies
by using fuslogvw.exe. It will allow you to create log files when the CLR
is run, and you can see what assemblies are loaded. Then, create an EXE,
adding any references that you want, but don't make any calls to types in
those assemblies. You will see they are not loaded.
 
|> As for the framework itself, the CLR is loaded into the process space
| > of EACH process it is in. If you have multiple app domains that are
| > running in the same process, then the CLR is loaded once for the
process.
| > However, if you have two apps in two separate processes, then the CLR is
| > loaded twice.
|
| Can you put thi in terms of RAM :-)? I think we are talking about the sme
| idea but maybe stating the same thing in different terms. If two separate
| processes use the same DLL, then the DLL executable code is _not_ loaded
| twice into RAM, the already-loaded executable code only exists in RAM
once,
| the code page is just re-mapped from the one instance in memory. Am I
right
| so far?
|
| Now the data page, the memory area that contains the memory that the DLL
is
| modifying, _does_ get duplicated for each app domain...
|
| In other words, given an executable code of a DLL that is 500K and the
data
| memory used by the DLL is 64K: If three app domains use the DLL/class
| library, 500K + 64K + 64K + 64K of memory will be used. Is this correct?
|
|

You must make a clear destiction between managed DLL's (assemblies) and
unmanaged DLL's.
Managed code DLL's (pure MSIL) are loaded per AD. the SMI and X86 code
(after JIT compiling) and data aren't shared amongst processes, nor are
they shared amongst AD's unless the assembly is loaded domain neutral.
The framework classes (a lot of them in v2) are pre-jitted native images,
that means that their code segments are shared amongst processes and
possible between AD's.
The CLR (written in native code) is only loaded once per proces and the code
segments are shared amongst (.NET) processes.

Willy.
 
Willy and Nichilas, thanks for this discussion on a somewhat
never-thought-about subject. It's quite refreshing to talk about .NET at
such a low, nuts and bolts level.
 
I concur Gabriel, it's great stuff!!!

On that note, Willy, when you say, "The CLR (written in native code) is
only loaded once per proces and the code
segments are shared amongst (.NET) processes. "

It sounds as though you are saying for each assembly loaded that does
not reference some group of assemblies but works with referenced
assemblies in the same process, the CLR is loaded once. For example:

[One CLR instance]
- A.exe loads - this loads a CLR instance. A.exe references B.dll
- B.dll loads into the A.exe app domain.

[Two CLR instances]
- A.exe loads same as above
- B.exe loads and only references X.dll. Another CLR instance loads
into the B.exe process. X.dll loads into the B app domain.

That right?

Thanks,
Brett
 
|I concur Gabriel, it's great stuff!!!
|
| On that note, Willy, when you say, "The CLR (written in native code) is
| only loaded once per proces and the code
| segments are shared amongst (.NET) processes. "
|
| It sounds as though you are saying for each assembly loaded that does
| not reference some group of assemblies but works with referenced
| assemblies in the same process, the CLR is loaded once. For example:
|
| [One CLR instance]
| - A.exe loads - this loads a CLR instance. A.exe references B.dll
| - B.dll loads into the A.exe app domain.
|

Yep.

| [Two CLR instances]
| - A.exe loads same as above
| - B.exe loads and only references X.dll. Another CLR instance loads
| into the B.exe process. X.dll loads into the B app domain.
|
| That right?
|

Yep.

Note that it's not quite correct to talk about CLR "instances", the CLR is
just a bunch of native code DLL's, and these DLL's are mapped into the
process address space. That means that and the "A" process and the "B"
process will each map the CLR DLL's. Note that I say 'mapped', that means
that while each process will get it's private copy of the non sharable pages
in the DLL (some of the data pages) loaded in the process address space,
each one will share the sharable pages (the code pages) accross the
processes. Now, this is exactly what the CLR is unable to do - share JIT
compiled code pages accross processes and AD's, but NGEN'd code can be
shared which is great for Terminal Server scenario's and other.

Willy.
 
Where does it say NGEN'd code "does" share code pages across processes?
I thought it was only for avoiding dynamic compilation.

Thanks,
Brett
 
Back
Top