这应该很简单。假设我有以下代码:
void Method()
{
AnotherMethod(new MyClass());
}
void AnotherMethod(MyClass obj)
{
Console.WriteLine(obj.ToString());
}
如果我调用“Method()”,在该过程中创建的MyClass对象会发生什么? 即使没有任何东西使用它,它是否仍然存在于堆栈中? 还是会立即被删除?
我是否必须将其设置为null以更快地使GC注意到它?
这应该很简单。假设我有以下代码:
void Method()
{
AnotherMethod(new MyClass());
}
void AnotherMethod(MyClass obj)
{
Console.WriteLine(obj.ToString());
}
在调用 Method 方法完成后,您的 MyClass
对象仍然存在于内存中,但没有根值引用它。因此,它会一直存在,直到下一次 GC 运行时收集它并回收内存。
实际上,您无法加速此过程,除非强制执行GC。但是这可能是一个坏主意。 GC 旨在清理这些对象,而您对其加速的任何尝试很可能导致整体变得更慢。您还会发现,虽然正确地清理托管对象,但 GC 可能实际上不会减少系统中的内存。这是因为 GC 将其保留以备将来使用。这是一个非常复杂的系统,通常最好让其自己操作。
void Method()
{
AnotherMethod(new MyClass());
Console.WriteLine("Hello world");
}
关闭优化后,我们有时会生成类似于以下代码的代码:
void Method()
{
var temp = new MyClass();
AnotherMethod(temp);
Console.WriteLine("Hello world");
}
BinaryFormatter
的意外序列化问题往往是由于事件订阅引起的,底层委托字段未标记为 [NonSerialized]
。您还可以使用字段式事件来实现此操作,如 [field:NonSerialized] public event EventHandler MyEvent;
。 - Marc Gravell实际上,该实例将在堆上声明,但请看Eric Lipper的文章The Stack is an Implementation Detail。
无论如何,因为函数执行后不会再有对该实例的引用,所以它可能会在未来某个未定义的时间点被垃圾收集器删除。关于确切的时间点,这是未定义的,但您基本上也不需要担心;GC有复杂的算法来帮助确定何时进行收集。
GC.KeepAlive()
必须存在的原因(尽管除非你真的非常需要,否则永远不应该使用该方法)。因此,将变量设置为null不应该有任何影响。 - Daniel Pryden垃圾回收器会跟踪哪些对象在代码中可能仍然被引用。然后,它会定期检查是否有任何仍然存活的对象不可能在代码中被引用,并清理它们。
这个机制有些复杂,垃圾回收的时间取决于各种因素。垃圾回收器旨在在最优化的时间(它可以确定的时间)进行这些回收,因此,虽然可以强制进行回收,但几乎总是一个坏主意。
将变量设置为null对对象处理的速度几乎没有影响。虽然在某些小的角落情况下可能会有所帮助,但这并不值得在代码中添加无用的赋值语句,这只会损害可读性而不会影响代码性能。
垃圾回收器旨在尽可能有效,而无需您考虑太多。老实说,您真正需要注意的唯一事情就是在分配长时间保持活动状态的大型对象时要小心,但在我的经验中,这种情况通常很少出现。