局部变量和垃圾生成

本文关键字:局部变量 | 更新日期: 2023-09-27 18:28:10

我的一段代码被反复调用(每秒2000多次)。为了避免垃圾生成并减少性能开销,我将所有局部变量移到了类级别,但我不确定这种方法是否有效。。。

我的问题是…

  • 垃圾收集器何时收集本地变量
  • 将局部变量移动到类级别是否可以提高性能并减少垃圾生成

局部变量和垃圾生成

变量不是垃圾收集的。对象已被垃圾收集。。。并且它们可以在运行时检测到它们不再被任何活动代码引用之后的任何时候被垃圾收集。这可以包括由局部变量引用的对象:
public void Foo()
{
    object x = new object();
    // The object can't be collected here...
    Console.WriteLine(x);
    // But it *can* be collected here
    Console.WriteLine("This line doesn't depend on x");
}

为了垃圾收集而改变"自然"设计很少是个好主意。。。方法的状态通常不是对象状态的自然组成部分,因此将局部变量转换为实例变量通常是个坏主意。

也就是说,我们不知道这些局部变量代表什么,也不知道它们的任何信息——我们需要更多的上下文来评论您的特定情况。

考虑这个非常简单的例子(其中SomeObject是一个类,而不是结构):

class C
{
  void MethodCalledMillionsOfTimes()
  {
    var so = new SomeObject();
    // some use of so
  }
}

每次调用该方法时,都会在堆上创建一个新对象。它需要在使用结束后的一段时间内进行垃圾收集。这是每个方法调用要收集的一个对象。

然后假设它被更改为:

class C
{
  SomeObject soField;
  void MethodCalledMillionsOfTimes()
  {
    soField = new SomeObject();
    // some use of soField
  }
}

这不会改变任何事情!仍然可以为每个方法调用创建一个新实例。垃圾收集器必须做同样数量的工作。

但如果你这样做了呢:

class C
{
  SomeObject soField = new SomeObject();
  void MethodCalledMillionsOfTimes()
  {
    // some use of soField
  }
}

这一次,每次在同一实例上再次调用该方法时,都会重复使用同一对象。因此,需要垃圾收集的对象更少(假设该方法实际上在同一个C对象上被多次调用)。请注意,只有当SomeObject实例可以多次使用,并且不会因每次使用而"破坏"其状态时,这才能起作用。

如果多个线程同时调用该方法,请确保对象soField能够处理该方法。

如果你进一步说:

class C
{
  static SomeObject soStaticField = new SomeObject();
  void MethodCalledMillionsOfTimes()
  {
    // some use of soStaticField
  }
}

则在CCD_ 5的所有实例之间仅共享一个对象。GC不必收集SomeObject

但是,这个GC活动通常对您的性能并不重要。因此,请衡量这对您的情况是否重要。