【问题标题】:When exactly are assemblies loaded?究竟什么时候加载程序集?
【发布时间】:2014-02-21 16:28:19
【问题描述】:

所以我试图准确了解 .NET 程序集何时加载到 .NET 进程中。我阅读了this blog entry,它很好地解释了事情,并证实了很多我认为我已经知道的东西,但它也提出了我认为我有点误解的一点。

依赖程序集在第一次被引用时及时加载 代码

我认为这意味着第一次调用程序集时,程序集被加载到程序中。因此,如果我有一个像下面的示例这样的程序,其中实例化 RasDialer 类的行将永远不会被调用 - 我相信 DotRas 程序集永远不会加载到进程中,我对此肯定是错误的。

但是,如果代码在我注释掉的部分中确实无法访问 - 那么程序集将永远不会加载,但似乎如果有机会,那么程序集将被加载。

这是我的小测试应用程序:

static void Main(string[] args)
{
    Console.WriteLine("Before");
    var dictionary = new Dictionary<int, string>();
    PrintAssemblies(); // <- DotRas is loaded here for null check variant

    if (dictionary == null)
    {
        // This line will never execute, but it does not matter
        var dialer = new RasDialer();
    }

    // DotRas will not be loaded if I uncomment this and comment 
    // out the other if statement since it is truly unreachable
    //if (false)
    //{
    //    var dialer = new RasDialer();
    //}

    Console.WriteLine(Environment.NewLine + "After");
    PrintAssemblies();

    Console.ReadLine();
}

public static void PrintAssemblies()
{
    var assemblies = AppDomain.CurrentDomain.GetAssemblies();
    foreach (var assembly in assemblies)
    {
        Console.WriteLine(assembly.GetName());
    }
}

有没有简单的方法来判断程序集何时加载到内存中?

在我在顶部链接的博客条目中 - 他的依赖程序集在他调用 PrintAssemblies() 之后才会加载,但对于我来说,依赖程序集在调用之前加载。所以它似乎并不容易预测。

如果 JIT 编译器可能需要依赖程序集中的类型,那么我是否正确地假设它会导致程序集被加载?

【问题讨论】:

    标签: .net .net-assembly jit


    【解决方案1】:

    只要检查了引用程序集的方法,就会加载程序集。

    大致就是在从 IL 转换为机器代码时。因此,只要您的方法引用了另一个程序集中的代码,该程序集就会被加载。

    因此,在您的示例中,包含 RasDialer 类的程序集将在第一次调用 Main 时加载,就在方法开始执行之前。

    您应该知道一些小方法是内联的(但可能不是在调试时)。因此,内联的代码将在内联后立即加载引用的程序集。

      void A(object arg0) {
          if (argO == null) {
            ClassFromAssembly1.Call();
            B();
            C();
          }
      }
    
      void B() {
          ClassFromAssembly2.Call();
      }
    
      [MethodImpl(MethodImplOptions.NoInlining)]
      void C() {
          ClassFromAssembly3.Call();
      }
    

    只要方法A 第一次被调用,就在方法A 的代码开始执行之前,Assembly1 和可能还有Assembly2 都会被加载。

    Assembly3 将在第一次调用 C 方法后立即加载。

    arg0 的值不能用于控制 Assembly1 的加载。何时加载 Assembly2,无法确定(取决于 B 的内联)。可以通过arg0的值来控制Assembly3的加载。

    【讨论】:

    • 那么这是否意味着如果 C() 从未被调用 - 为了与我对从未评估为 true 的 if 语句的问题保持一致,请说。永远不会通过NoInlining 选项加载程序集?
    • 我已经更新了我的答案。 NoInlining 防止 C 被内联。这使您可以更好地控制何时加载引用的程序集。
    猜你喜欢
    • 1970-01-01
    • 2020-10-30
    • 2021-04-15
    • 2014-09-09
    • 2017-12-11
    • 2023-02-25
    • 2015-10-12
    • 2019-12-31
    • 2011-08-19
    相关资源
    最近更新 更多