为什么未收集未引用的对象?
Why an unreferenced object is not collected?
此程序将 "True" 打印到控制台。
分配一个对象,对其进行弱引用,超出块范围,并检查 WeakReference.IsAlive。
public static void Main (string[] args)
{
Test ();
}
static void Test ()
{
WeakReference wref = null;
{ // block scope
var obj = new object ();
wref = new WeakReference (obj);
}
// obj is out of scope
// Console.WriteLine (obj);
GC.Collect ();
Console.WriteLine (wref.IsAlive); // => True
}
为什么没有收集到 obj,尽管 obj 超出了范围?
程序由Mono 3.12.0编译。
编辑:
抱歉,示例不当。
以下程序也打印 True。块范围似乎不相关。
这是尝试 not 与 Debug 模式。
public static void Main (string[] args)
{
Test ();
}
static void Test ()
{
WeakReference wref = null;
var obj = new object ();
wref = new WeakReference (obj);
obj = null;
GC.Collect ();
Console.WriteLine (wref.IsAlive); // => True
}
$ mcs -debug- Program.cs
$ mono Program.exe
因为你 运行 我猜是在调试器中。
尝试运行发布版本,然后运行在调试器之外手动运行它。
您希望 GC 是 100% 确定性的,但事实并非如此。
可能发生的一些事情:
- JIT 优化了空赋值。
- 指向实例的指针可以留在临时堆栈位置或寄存器中(您调用了一个函数,传递了变量,这会将变量放入某些体系结构的寄存器中)。
在GC.Collect后添加:
GC.WaitForPendingFinalizers();
通过调用此过程,所有可终结对象都可以在继续您的程序之前执行任何必要的清理。它确保您的代码不会调用当前正在销毁的对象上的方法。
此程序将 "True" 打印到控制台。
分配一个对象,对其进行弱引用,超出块范围,并检查 WeakReference.IsAlive。
public static void Main (string[] args)
{
Test ();
}
static void Test ()
{
WeakReference wref = null;
{ // block scope
var obj = new object ();
wref = new WeakReference (obj);
}
// obj is out of scope
// Console.WriteLine (obj);
GC.Collect ();
Console.WriteLine (wref.IsAlive); // => True
}
为什么没有收集到 obj,尽管 obj 超出了范围?
程序由Mono 3.12.0编译。
编辑:
抱歉,示例不当。
以下程序也打印 True。块范围似乎不相关。 这是尝试 not 与 Debug 模式。
public static void Main (string[] args)
{
Test ();
}
static void Test ()
{
WeakReference wref = null;
var obj = new object ();
wref = new WeakReference (obj);
obj = null;
GC.Collect ();
Console.WriteLine (wref.IsAlive); // => True
}
$ mcs -debug- Program.cs
$ mono Program.exe
因为你 运行 我猜是在调试器中。
尝试运行发布版本,然后运行在调试器之外手动运行它。
您希望 GC 是 100% 确定性的,但事实并非如此。
可能发生的一些事情:
- JIT 优化了空赋值。
- 指向实例的指针可以留在临时堆栈位置或寄存器中(您调用了一个函数,传递了变量,这会将变量放入某些体系结构的寄存器中)。
在GC.Collect后添加:
GC.WaitForPendingFinalizers();
通过调用此过程,所有可终结对象都可以在继续您的程序之前执行任何必要的清理。它确保您的代码不会调用当前正在销毁的对象上的方法。