什么是SQL Server CLR集成生命周期?

如何在SQL Server中管理CLR(.NET)对象?

SQL Server中任何CLR代码的入口点都是静态方法。 通常,您只会创建该方法范围内的对象。 但是,您可以设想在静态成员中存储对象的引用,让它们转义方法调用范围。 如果SQL Server在多个存储过程/函数调用中将这些对象保留在内存中,那么它们对于缓存应用程序可能很有用 – 尽管它们也更危险。

SQL Server如何处理这个问题? 它甚至允许(非方法)静态成员吗​​? 如果是这样,它在记忆中保留了多长时间? 在每次CLR呼叫之后垃圾收集所有内容吗? 它如何处理并发?

在Robin Dewson和Julian Skinner的“Pro SQL Server 2005 Assemblies”中,它表示“像其他数据库对象一样加载到数据库中的程序集由数据库用户拥有。同一用户在同一数据库中拥有的所有程序集都将运行在同一AppDomain中。由不同用户拥有的程序集将在单独的AppDomain中运行。“

这告诉我的是,如果您正在使用单个数据库并且使用CREATE ASSEMBLY语句加载的所有程序集具有相同的所有者,那么您的程序集将全部在同一个应用程序域中运行。 但是,在同一个AppDomain中并不意味着使用相同的代码库,因此即使相同的dll也可以多次加载到同一个应用程序域中,即使它们具有相同的名称,它们的类型也不会匹配。 当同名类型来自不同的代码库时,它们的静态变量也将是不同的实例。

我可以看到在具有多个程序集的SQL Server CLR环境中安全地使用静态变量的唯一方法是实际上只使用单个程序集。 您可以将ILMerge实用程序与“UnionMerge”选项一起使用,将所有程序集打包为一个并合并具有相同名称的类。 这应该保证对于给定的数据库,在您的单独程序集中,您的静态变量将像在独立应用程序中一样工作。 我认为可以安全地假设应用程序域没有被卸载并在每次请求时重新加载,但是你不能依赖它永远不会被卸载,因为只要有未处理的错误就会发生这种情况(至少如果它在不安全的模式下运行) )。

不可想象; 你可以创建静态成员。 但是,对于具有SAFEEXTERNAL_ACCESSPERMISSION_SET的程序集,它们需要被标记为readonly 。 只有标记为UNSAFE的程序集才能具有可写静态成员。 而这种限制是由于静态成员的本质:它们在线程和会话之间共享。

第一次访问其中的方法时加载程序集。 它被共享用于所有会话,这就是为什么只能访问静态方法。 想法是编写函数,而不是应用程序,因此在保持状态方面没有太多用处。 如果各种会话相互覆盖,它很容易(但肯定不会总是)导致不可预测的行为。 因此,除非您自己编写该部分,否则根本不会处理并发性。

应该可以预期,一旦加载,类(以及它所驻留的App Domain)将保留在内存中,直到SQL Server服务重新启动或PERMISSION_SET值更改为止。 但这不能保证。 根据此页面, SQL CLR中的内存使用情况 :

当服务器上存在内存压力时,SQL CLR将尝试通过显式运行垃圾收集来释放内存,并在必要时卸载appdomains。

所以关于静态成员的两个方面都是正确的:

  • 它们可以用于缓存(非常酷)
  • 他们可能更危险:
    • 它们可能会导致意外行为
    • 它们可以占用内存,因为没有固有的机制或自然事件来清理它们因为课程保持活跃。

并且,可用于CLR例程的内存量会有很大差异,具体取决于SQL Server是32位还是64位,以及您使用的是SQL Server 2005/2008 / 2008 R2还是使用SQL Server 2012/2014。有关详细信息内存SQLCLR必须使用,查看SQL CLR中的 SQL Server 2012内存和内存使用情况 (与第一个链接相同,发布在引号上方)。

这是我发现的一些信息。

在SQLCLR中使用共享状态和匿名委托进行故障

不仅在非UNSAFE程序集中不允许共享状态,但匿名委托(不幸的是)会触发此“共享状态”限制。

来自C#规范3.0(5.1.1)

静态变量在执行其包含类型的静态构造函数(第10.12节)之前就已存在,并且在关联的应用程序域不再存在时不再存在。

当然,在每次调用之后它不会关闭整个应用程序域,因为它会有点低效。 所以,只要数据库没有停止或重新启动,这些静态对象就会保留在那里。