Ratio between Managed and Native Modules

There is not always a 1:1 correlation between Managed modules and native modules. For example,

  1. Sometimes it's (managed:unmanaged) 1:1. (Normal file-based modules) This is the common case, so people tend to assume it's always true. Regular file-based managed modules are implemented on top of native modules. So if you load C# module foo.dll, the process is loading a native module foo.dll which shows up in the native module lists.
  2. Sometimes it's 1:0. (In-memory modules) However, the CLR can have managed modules that don't have a native module counterpart. For example, the CLR supports purely in-memory modules (Assembly.Load(Byte []). Also, ref.Emit (and services built on that like CodeDom) can create pure in-memory modules too.  These don't have any associated native module.
  3. Sometimes it's 1:2. (Ngen) Ngen images are implemented on top of native modules, so a managed foo.dll may show up as foo.ni.dll (see debugging ngen code for more details). Thus a single managed dll (foo.dll) may correspond to 2 native dlls (foo.dll, foo.ni.dll)
  4. Sometimes it's n:1. (Domain-neutral Sharing). As an optimization, the CLR can share certain modules (such as mscorlib) across multiple appdomains. So there will be 1 native module loaded under the hood for the entire process, but it will appear as 1 managed module in each appdomain.

There are probably more combos I'm missing.

Other trivia:

  1. Windows has some nice APIs for viewing native module lists, like kernel32!CreateToolHelp32Snapshot.  There are nice tools too, like listdlls.exe.
  2. Viewing the native-modules is a rough approximation for the managed modules, and is often good enough. But the only correct way to view all managed modules is via the ICorDebug, the managed debugging API.  Here's a sample to view managed modules.
  3. The System.Diagnostics.ProcessModule class represents native modules, because it's just a wrapper around the APIs for enumerating native modules. So don't think that just because it's a C# API, that it only aplies to C# constructs!
  4. When interop-debugging, the module window will show both managed and native modules (and it will tell you which is which). Since some managed modules are built on native modules, you'll see 2 entires in the module window. One will be managed, and one will be native.