我的一段代码被重复调用(每秒 2000+)。为了避免垃圾生成并降低性能开销,我将所有局部变量移至类级别,但我不确定这种方法是否有效......
我的问题是...
- 垃圾收集器何时收集局部变量?
- 将局部变量移动到类级别会提高性能并减少垃圾生成吗?
我的一段代码被重复调用(每秒 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
}
}
那么 . 的所有实例之间只有一个对象共享C
。没有SomeObject
将必须由 GC 收集。
但是,此 GC 活动通常对您的性能并不重要。因此,请衡量它是否对您的情况重要。