即使对象超出范围,Dotnet 也不会调用其终结器。那么如何释放非托管资源呢?
Dotnet not calling its finalizer even if the object goes out of scope. How to release unmanaged resources then?
我尝试使用以下代码
[DllImport("Core.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr CreateNode();
[DllImport("Core.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern void ReleaseNode(IntPtr handle);
class Node
{
IntPtr nativePtr;
public int id;
public Node(int i)
{
nativePtr = CreateNode();
id = i;
Debug.WriteLine("Constructed " + id);
}
~Node()
{
ReleaseNode(nativePtr);
Debug.WriteLine("Destructed " + id);
}
}
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
Node n = new Node(i);
} //this scope
}
}
在 for
循环内创建的 Node
class 的每个对象在离开 for 循环作用域(评论为 "this scope")后不会被破坏。仅当 Main 方法的作用域结束时才调用它。是否可以在 for 循环作用域结束时自动调用 ~Node?
在执行上述代码时,我在调试中得到以下信息 window。
Constructed 0
Constructed 1
Constructed 2
Constructed 3
Constructed 4
Constructed 5
Constructed 6
Constructed 7
Constructed 8
Constructed 9
Destructed 9
Destructed 0
Destructed 8
Destructed 7
Destructed 6
Destructed 5
Destructed 4
Destructed 3
Destructed 2
Destructed 1
这表明最先构造的对象最后被破坏。如果发生这种情况,当我 运行 数以千计的项目循环时会发生什么?
它会消耗我所有的记忆吗?
如何完美释放我的非托管资源?
TL;DR:如果可能,去掉终结器,相信垃圾收集器会做正确的事情。
最终确定是不确定的。重要的是要了解 objects 不会超出范围;对象没有开始的范围。 变量超出范围,不会触发任何东西。
通常,垃圾收集器只在需要时运行。无法保证调用终结器的顺序或调用它们的时间。 (虽然您可以请求垃圾收集器运行,但这通常是个坏主意,而且几乎没有任何保证。)
不过,在您自己的终结器中使用终结器几乎总是一个坏主意 类:它会延迟实际的垃圾收集,而且无论您在终结器中做什么,几乎总是有更好的方法。
C#(和一般的 .Net Framework)使用 Garbage Collector to manage memory, so you shouldn't need to worry about that. If you're coming from c++, this might be feel a little strange at first, but GC does it's job pretty well. Finalizers 由垃圾收集器调用,文档明确说明:
The programmer has no control over when the finalizer is called
because this is determined by the garbage collector.
如果您有一个 class 占用大量资源并且您想控制何时释放资源,您应该使用 IDisposable
和 using
语句。
调用终结器由垃圾收集器完成。要完美控制非托管资源,请使用一次性模式
class MyResource : IDisposable
{
~MyResource()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this); // don't finalize after the object has already been disposed of
}
protected void Dispose(bool disposing)
{
if(disposing)
{
// TODO: Dispose managed resources
}
// TODO: Dispose unmanaged resources
}
}
// when using
using(var resource = new MyResource())
{
// ... use resource
} // when out of "using" scope, it will be disposed
我尝试使用以下代码
[DllImport("Core.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr CreateNode();
[DllImport("Core.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern void ReleaseNode(IntPtr handle);
class Node
{
IntPtr nativePtr;
public int id;
public Node(int i)
{
nativePtr = CreateNode();
id = i;
Debug.WriteLine("Constructed " + id);
}
~Node()
{
ReleaseNode(nativePtr);
Debug.WriteLine("Destructed " + id);
}
}
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
Node n = new Node(i);
} //this scope
}
}
在 for
循环内创建的 Node
class 的每个对象在离开 for 循环作用域(评论为 "this scope")后不会被破坏。仅当 Main 方法的作用域结束时才调用它。是否可以在 for 循环作用域结束时自动调用 ~Node?
在执行上述代码时,我在调试中得到以下信息 window。
Constructed 0
Constructed 1
Constructed 2
Constructed 3
Constructed 4
Constructed 5
Constructed 6
Constructed 7
Constructed 8
Constructed 9
Destructed 9
Destructed 0
Destructed 8
Destructed 7
Destructed 6
Destructed 5
Destructed 4
Destructed 3
Destructed 2
Destructed 1
这表明最先构造的对象最后被破坏。如果发生这种情况,当我 运行 数以千计的项目循环时会发生什么? 它会消耗我所有的记忆吗?
如何完美释放我的非托管资源?
TL;DR:如果可能,去掉终结器,相信垃圾收集器会做正确的事情。
最终确定是不确定的。重要的是要了解 objects 不会超出范围;对象没有开始的范围。 变量超出范围,不会触发任何东西。
通常,垃圾收集器只在需要时运行。无法保证调用终结器的顺序或调用它们的时间。 (虽然您可以请求垃圾收集器运行,但这通常是个坏主意,而且几乎没有任何保证。)
不过,在您自己的终结器中使用终结器几乎总是一个坏主意 类:它会延迟实际的垃圾收集,而且无论您在终结器中做什么,几乎总是有更好的方法。
C#(和一般的 .Net Framework)使用 Garbage Collector to manage memory, so you shouldn't need to worry about that. If you're coming from c++, this might be feel a little strange at first, but GC does it's job pretty well. Finalizers 由垃圾收集器调用,文档明确说明:
The programmer has no control over when the finalizer is called because this is determined by the garbage collector.
如果您有一个 class 占用大量资源并且您想控制何时释放资源,您应该使用 IDisposable
和 using
语句。
调用终结器由垃圾收集器完成。要完美控制非托管资源,请使用一次性模式
class MyResource : IDisposable
{
~MyResource()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this); // don't finalize after the object has already been disposed of
}
protected void Dispose(bool disposing)
{
if(disposing)
{
// TODO: Dispose managed resources
}
// TODO: Dispose unmanaged resources
}
}
// when using
using(var resource = new MyResource())
{
// ... use resource
} // when out of "using" scope, it will be disposed