C# static

2023-10-25 10:52:58 浏览数 (3)

在 C# 中,static 关键字被用来标识一个成员(变量、方法、属性等)属于类自身,而不是类的实例。这意味着,无论我们创建多少个类的实例,都只会有一个 static 成员的副本。static 成员保存在 CLR (Common Language Runtime) 的静态内存中,而非堆或栈。

关于 static 存储的一些主要特点:

  1. 生命周期: static 变量的生命周期与程序的生命周期相同。当程序开始时,它们被初始化,当程序终止时,它们被销毁。
  2. 存储位置: static 变量存储在托管堆(Managed Heap)上的高频段,而不是与对象实例一起存储。
  3. 共享性: 所有实例共享同一个 static 变量。
  4. 初始化: static 变量在 .NET CLR 加载包含该变量的类时被初始化。如果是值类型,将被初始化为其默认值;对于引用类型,如果没有明确赋值,将被初始化为 null
  5. 访问方式: static 变量可以直接通过类名进行访问,而不需要对类进行实例化。

static 在 C# 中充当了全局变量的角色,并且提供了一种控制变量生命周期和访问权限的方式。

什么是高频段(High Frequency Heap)

.NETCommon Language Runtime (CLR) 管理了一个叫做“高频段”(High Frequency Heap)的内存区域,它专门用于存储静态字段。换句话说,高频段是托管堆中的一块特殊区域,主要用于存储所有类型的静态字段。

以下是一些关于高频段的重要说明:

  1. 生命周期:由于静态字段共享在整个应用程序实例中,并且它们的生命周期与应用程序运行周期相同,因此这部分内存在应用程序启动时就被分配,并且在应用程序关闭时释放。
  2. 访问速度:通常来说,访问位于高频段的静态字段比访问常规托管堆的对象更快。这主要是因为这些字段在物理内存中的位置固定不变,所以可以直接访问。
  3. 引用类型的处理:对于引用类型的静态字段,其引用(即地址)保存在高频段,但其实际指向的对象数据仍然存储在托管堆的其他部分。

static修饰的含义

static 关键字可以用于修饰类的成员(变量、方法、属性)和类本身。每种情况下 static 的含义略有不同:

  1. 静态变量 (static variables): 当我们将变量声明为静态时,无论创建多少个类的实例,都只会有一个静态变量的副本。所有的实例都共享该静态变量。您可以直接通过类而不是类的实例来访问静态变量。
  2. 静态方法 (static methods): 静态方法也是与类相关联,而非类的实例。因此,无需创建类的实例即可调用静态方法。静态方法只能访问静态变量或其他静态方法,它们不能访问类的非静态成员。
  3. 静态属性 (static properties): 静态属性用于获取或设置静态数据成员的值。它们的工作方式类似于静态方法。
  4. 静态类 (static classes): 静态类是一种特殊类型的类,它不能被实例化。换句话说,如果你试图创建静态类的实例,编译器会报错。静态类只包含静态成员。这些类通常用于存储不会改变的数据或全局方法,例如 System.Math 类。

记住,static 成员是类级别的,不是实例级别的。静态成员属于整个类,而不是类的特定实例。

优点:

  1. 内存效率: 使用 static 可以提高内存的使用效率。由于 static 成员与类相关联,不论实例化多少个类,对于每个 static 成员都只会有一个副本。
  2. 全局访问: static 成员可以在没有创建对象的情况下被访问,因此它们可以被看作是全局变量。
  3. 生命周期: static 变量的生命周期为整个程序周期,因此可以用来存储在应用程序执行期间需要持久存在的信息。
  4. 控制实例数目: 通过将类的构造函数声明为 static,可以防止类被实例化,从而控制类的实例数量。

缺点:

  1. 内存占用: 尽管 static 变量在某些情况下可以提高内存效率,但由于它们在整个程序周期内都保持在内存中,因此可能导致过度的内存使用。
  2. 测试难度: static 成员可能使单元测试变得困难,因为它们在所有测试案例中都保持状态。这可能导致一些副作用,影响测试结果。
  3. 并发问题: 在多线程环境中,static 变量需要额外的同步措施以防止竞态条件。
  4. 面向对象设计: 过度使用 static 可能会破坏面向对象的设计原则,如封装、继承和多态,因为 static 成员不能通过类的实例进行访问或重写。

静态变量不再被使用时,如何回收内存空间?

都知道静态变量的生命周期持续整个应用程序的运行期,然而有些策略可以帮助我们有效管理静态变量:

  1. **设为 null**:如果你确定一个静态变量不再需要使用,可以把它设置为 null。虽然这种做法并不能立即释放内存,但会让 .NET 的垃圾收集器(GC)在下一次运行时回收该内存区域。
  2. 避免过度使用静态变量:如果你担心静态变量导致的内存问题,可能最好的解决方案就是尽量避免使用静态变量。如果一个变量可以不是静态的,最好使它成为实例变量。这样,每当相关对象实例不再被引用时,垃圾收集器就能释放与该实例关联的内存。
  3. 使用 WeakReference:对于大型对象或数据结构,可以考虑使用 WeakReferenceWeakReference 允许其引用的对象被垃圾收集器回收,在没有强引用存在的情况下。

静态变量的内存管理是由 .NET Common Language Runtime (CLR) 自动处理的,并且开发者不能直接控制。

1 人点赞