ASP.NET静态变量的生命周期


78

我将某些信息保存在页面类(而不是Global.asax)中定义的静态变量中。我只在代码中声明变量,例如:

protected static int SomeGlobalUnsecureID;
protected static string SomeGlobalUnsecureString;

并在PageLoad事件中定义变量。例如,我从数据库中检查ID,如果它与SomeGlobalUnsecureID不同,则从其他位置更新SomeGlobalUnsecureID和String,否则将其保留不变。这在我的应用程序中绝对安全。逻辑(即那些数据不安全,每个人都可以访问它们,没问题);我唯一想完成的是

  1. 无论连接的用户是什么,都保持相同数量的内存

  2. 仅当持久性信息与“内存”中的信息不同时才更改(因为实际读取字符串对我来说很耗时。

现在,由于我在PageLoad中进行了检查,所以重新加载的页面没有问题。但是,我的页面上充满了WebMethods,有时我看到静态变量被清零。而奇怪的是:即使静态变量为零,会话仍处于活动状态(因此->没有服务器或应用程序池重启等)

这对我来说真的很奇怪。我假设静态变量将保持其值,直到应用程序(以某种方式)结束。但是,即使会话未到期,静态变量也将清零。你有什么建议?使用应用程序变量是更好的选择吗?我在网上阅读的所有文档都建议使用静态变量而不是应用程序变量,是否需要以某种方式声明它们?


1
问题顶部的声明不是静态的,顺便说一句。
安德鲁·巴伯

1
'在PageLoad事件中定义变量。我想你是说初始化?定义变量是您在编写时正在执行的操作protected static int Something;
Carl G

“现在,由于我在PageLoad中进行了检查,因此重新加载的页面没有问题。” -这听起来像是在等待比赛条件的发生。我会考虑使用线程安全的惰性初始化。
millimoose

静态激光持续到下一次循环。将变量放在静态类中,然后在其他类中使用
Mbithy Mbithy

Answers:


105

静态变量在应用程序域的生命周期内一直存在。因此,导致您的静态变量“重置”的两件事是应用程序域重启或使用新类。对于将静态变量存储在aspx Page类中的情况,当ASP.NET决定将aspx Page重新编译为新类时,您可能会丢失静态变量,用新的类替换旧的页面类。

由于这些原因,如果系统决定重新启动或替换该类(.NET不会杀死正在运行的应用程序域中的类/程序集),则您的静态变量将重置,因为您将通过重新启动或替换获得一个新的类。这适用于aspx页面和App_Code文件夹中的类

如果出于任何原因认为需要重新编译该类,则ASP.NET将替换该类(请参见ASP.NET动态编译)。

您无法防止由于应用程序域重启而丢失静态变量,但是您可以尝试避免在类替换中使用它。您可以将静态变量放在不是aspx页且不在App_Code目录中的类中。您可能需要将它们放在static class程序中的某个位置。

public static class GlobalVariables
{
    public static int SomeGlobalUnsecureID;
    public  static string SomeGlobalUnsecureString;
}

静态变量是每个池的,这意味着如果您有2个运行asp.net站点的池,则您将有2个不同的静态变量。(网络花园模式

如果系统使用这种方式之一重新启动asp.net应用程序,则静态变量将丢失。

  1. 池决定需要重新编译。
  2. 您打开app_offline.htm文件
  3. 您手动重新启动池
  4. 池已达到您定义的一些限制,然后重新启动。
  5. 出于任何原因,您都将重新启动iis或池。

此静态变量不是线程安全的,如果您从其他线程访问它们,则需要使用特殊的lock关键字。

由于重新启动应用程序无论如何都将重置您的静态信息,因此,如果您确实要保留数据,则应使用自定义类将数据存储在数据库中。您可以存储每个用户的信息会话状态数据库会话状态模式。ASP.NET应用程序状态/变量将无法为您提供帮助,因为它们存储在内存中,而不是数据库中,因此它们也会在应用程序域重新启动时丢失。


6
@Aristos这可能是一个古老的问题,但您的答案不正确。如果一个类变量是静态的,则无论您创建和杀死该类的多少实例都无所谓,只要该变量的程序集保持加载到内存中,该变量仍将保持其值。但是,由于IIS定期回收托管的应用程序,因此某些程序集将被卸载然后再次加载,从而导致静态变量数据丢失。看看这个
Thomas CG de Vilhena 2012年

1
@ ThomasC.G.deVilhena我跟你说(同意)同样的话吗?打字不好吗?您能否编辑我的问题并更正您所说的这一部分?
亚里斯多斯

1
我认为问题在于静态变量是在aspx文件中定义的(必须是非静态类。)除了应用程序重新启动(擦除所有静态变量)之外,IIS还会重新编译aspx页(修改它们后,或可能出于其他原因),然后加载新的已编译程序集。新编译的aspx页面/类是具有自己的静态变量的新类。将变量切换到静态类应该防止重置,除非在应用程序重新启动的情况下,因为现在该类不再发生aspx重新编译。
卡尔·G

1
@ ThomasC.G.deVilhena如果您想更改此答案的某些部分以使其更准确,请这样做。
亚里斯斯托里斯

1
@CarlG我也向您建议,如果您想更改此答案的某些部分,或添加一些其他方面以使其更准确,请这样做。
亚里斯多斯

20

我认为以下两点对于静态变量的生命周期也很重要:

1-在应用程序池的高级设置中,选中“回收”->“常规时间间隔(分钟)”设置。它的默认值是1740,这意味着每29个小时您的静态变量会由于应用程序池的回收而丢失。此设置用于终止可能的内存泄漏。我不会更改此设置。

2-在应用程序池的高级设置中,检查“过程模型”->“空闲超时(分钟)”设置。它的默认值为20,这意味着在应用程序池中每20分钟不活动时,工作进程将被终止/挂起,这将导致您的静态变量丢失。当一段时间未使用应用程序池时,此设置用于释放资源。您可以将其设置为0以禁用超时。


1
谢谢。就我而言,回收是问题所在。
艾萨克(Isaac)

恕我直言,对于大多数应用程序,默认回收设置应更改,因为它会“移动”-我想我很想确切地知道池何时将回收而无需考虑。
fightc2

-11

静态变量用于存储所有具有相同值的对象

protected void Page_Load(object sender, EventArgs e)
{
    sss s1, s2;
    s1 = new sss();
    s1.TotalMark = 10;
    s2 = new sss();
    s2.TotalMark = 20;
    sss.SchoolName = "St.Joseph's Hr.Sec.S"; //We can access through class and assign common to all
    s1.PrintData();
    s2.PrintData();
}

public class sss
{
    public static string SchoolName { set; get; }
    public int TotalMark { set; get; }
    public string StudentName{set;get;}
    public void PrintData()
    {
        Console.WriteLine(TotalMark);
        Console.WriteLine(SchoolName);
        Console.WriteLine(StudentName);
    }
}

3
否决,这个答案与问题无关。(OP清楚地了解了静态变量应该如何工作。-问题是为什么它们不能正确工作。)-此外,解释措辞很差。
BrainSlugs83 '02
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.