显式定义范围的方法。
static void Main(string[] args)
{
Class1 c1 = new Class1(1);
{
Class1 c2 = new Class1(2);
{
Class1 c3 = new Class1(3);
}
//this is not collecting object c3 which is out of scope here
GC.Collect();
}
//this is not collecting object c2 which is out of scope here
GC.Collect();
Console.ReadKey();
}
Class1定义:
class Class1
{
int x;
public Class1(int a)
{
x = a;
}
~Class1()
{
Console.WriteLine(x + "object destroy");
}
}
我写这段代码。但是GC.Collect()方法不会收集超出范围的对象。
答案 0 :(得分:2)
GC.Collect()
并不真正意味着用于确定性的资源回收。 (这就是你的真实代码中的终结器正在做什么,对吗?)
如果您有非托管资源需要处理,请考虑使用Microsoft.Win32.SafeHandles
中的某个类。
如果您想要确定性地释放资源,则应该实现IDisposable
,并在完成使用该对象后调用Dispose()
。这样做的惯用方法是:
using (var someResource = new Class1(1))
{
// work with the `Class1` object
}
在功能上等同于
{
var someResource = new Class1(1);
try
{
// work with the `Class1` object
}
finally
{
someResource.Dispose();
}
}
答案 1 :(得分:0)
您对范围界定的看法是正确的。对象超出了您的预期范围。但是,显然你测试它的方式并不正确。
这里要考虑几点。
只有当有任何非托管资源时,才应实施终结器。 如果你的类有一个终结器,并且如果你没有以implement IDisposable Correctly的方式抑制终结,那么该类的实例可以驻留在内存中两个垃圾收集周期。因为,如果需要完成,第一个GC.Collect会将该实例添加到终结队列。可能是第二个垃圾收集周期实际上清除了内存。
Finalizer是.net对象可以释放非托管资源的最后一点。 仅当您未正确处理实例时才会执行终结器。理想情况下,决不应该执行终结器。因为适当的处置实施应该抑制最终确定。
根据您的示例代码,如果您致电GC.Collect and WaitForPendingFinalizers,您的测试可能会通过(不确定如何查找是否已清除内存)。
更好地测试你。
清除内存时,垃圾收集器不会考虑内部作用域。如果将代码移动到单独的方法中,则执行终结器。
测试1
static void Main(string[] args)
{
GCTest();
Console.ReadKey();
}
private static void GCTest()
{
Class1 c1 = new Class1(1);
{
Class1 c2 = new Class1(2);
{
Class1 c3 = new Class1(3);
}
//this is not collecting object c3 which is out of scope here
GC.Collect();
GC.WaitForPendingFinalizers();
}
//this is not collecting object c2 which is out of scope here
GC.Collect();
GC.WaitForPendingFinalizers();
}
测试2
如果要为垃圾收集目的指定范围,请使用using statement。
private static void Main(string[] args)
{
using (Class1 c1 = new Class1(1))
{
using (Class1 c2 = new Class1(2))
{
Class1 c3 = new Class1(3);
}
}
Console.ReadKey();
}
class Class1 : IDisposable
{
int x;
public Class1(int a)
{
x = a;
}
public void Dispose()
{
Console.WriteLine(x + "object disposing");
}
}
输出
2对象处理
1对象处理
答案 2 :(得分:0)
这些范围不会成为IL。运行时不知道他们在那里。在IL级别,只有本地和堆栈内容。虽然.NET JIT一般很差,但它可以很好地将本地和临时值优化成一种有效的形式。
无法保证何时收集对象。 GC.Collect
无法强制执行此操作。有一些安全模式可以保证99.999%,但永远不会完全。
你永远不需要这个设施。事实上,拥有终结器的需求几乎为零。使用SafeHandle
基础架构。
如果您真的想看到效果,请将所有这些代码移到辅助方法中并从Main
调用它。回到主页,Collect
将成功。