感谢baihaixiao 的这篇博文。
还有xmsheji的这篇。
还有这篇。
在写c#处理数据很多,处理完每次都占用很大内存,释放不掉,很是不爽。
搞明白一点c#的垃圾回收,把测试代码备份一下
//代码来源浅谈C#的垃圾回收-关于GC、析构函数、Dispose、and Finalize
//http://blog.csdn.net/baihaixiao/article/details/4583910
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.IO;
using System.Data.SqlClient;
namespace ConsoleApplication3
{
class Log
{
public static readonly string logFilePath = @"d:/log.txt";
public static void Write(string s)
{
Thread.Sleep(10);
using (StreamWriter sw = File.AppendText(logFilePath))
//此处有可能抛出文件正在使用的异常,但不影响测试
{
sw.WriteLine("{0}\tTotalMilliseconds:{1}\tTotalMemory:{2}", s,
DateTime.Now.TimeOfDay.TotalMilliseconds, GC.GetTotalMemory(false));
sw.Close();
}
}
}
class World
{
protected FileStream fs = null;
protected SqlConnection conn = null;
public World()
{
fs = new FileStream(Log.logFilePath, FileMode.Open);
conn = new SqlConnection();
}
protected void Finalize()
{
fs.Dispose();
conn.Dispose();
Log.Write("World's destructor is called");
}
}
class China : World
{
public China()
: base()
{
}
~China()
//protected void Finalize()
//若改为Finalize则覆盖了父类的Finalize导致无法调用父类的Finalize
{
Log.Write("China's destructor is called");
}
}
class Beijing : China
{
public Beijing()
: base()
{
}
~Beijing()
{
Log.Write("Beijing's destructor is called");
}
}
class Program
{
static void Main(string[] args)
{
// new Beijing();
//GC.Collect();
//GC.WaitForPendingFinalizers();
//Log.Write("In TestOne../t/t");
TestOne();
Log.Write("In Main..\t\t");
}
static void TestOne()
{
//new Beijing();
//GC.Collect();
//GC.WaitForPendingFinalizers();
//Log.Write("In TestOne..\t\t");
new Beijing();
GC.Collect();
Log.Write("In TestOne..\t\t");
//以下这句异常通不过,log文件没有输出,不像博主说的那样
//Beijing bj = new Beijing();
//GC.Collect();
//Log.Write("In TestOne..\t\t");
}
}
}
/*
* 在C#中,如果一个自定义类没有构造器,编译器会添加一个隐藏的无参构造器。但是析构函数不会自动创建。
* 一旦析构函数创建了,终结器也便自动产生了。构构函数其实等同于如下代码:
try{
Finalize();
}finally{
base.Finalize();
}
* 如果在派生类中不存在析造函数,却重载了基类的终结器,如下:
protected override void Finalize(){...}
垃圾回收时,GC找不到析构函数,会直接调用终结器。因终结器已重写,如果在该终结器中不调用基类的终结器,
* 那么GC将忽略基类。可以利用这个特性写一个不受垃圾回收器管辖的类,以实现某种特殊的效果。
输出结果:
new Beijing();
GC.Collect();
GC.WaitForPendingFinalizers();
Log.Write("In TestOne..\t\t");
new Beijing();
GC.Collect();
Log.Write("In TestOne..\t\t");
//TestOne中有GC.WaitForPendingFinalizers();
Beijing's destructor is called TotalMilliseconds:31906036.8852 TotalMemory:374872
China's destructor is called TotalMilliseconds:31906050.886 TotalMemory:391256
World's destructor is called TotalMilliseconds:31906061.8867 TotalMemory:415832
In TestOne.. TotalMilliseconds:31906076.8875 TotalMemory:440408
In Main.. TotalMilliseconds:31906087.8882 TotalMemory:456792
//TestOne中无GC.WaitForPendingFinalizers();
Beijing's destructor is called TotalMilliseconds:32140815.498 TotalMemory:391256
In TestOne.. TotalMilliseconds:32140816.4981 TotalMemory:407640
China's destructor is called TotalMilliseconds:32140826.4986 TotalMemory:424024
In Main.. TotalMilliseconds:32140829.4988 TotalMemory:448600
World's destructor is called TotalMilliseconds:32140843.4996 TotalMemory:473176
*
*
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
AA a;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
a = new AA("D://a.txt");
//a.Dispose();
//AA b = new AA();
//AA c = new AA();
//AA d = new AA();
// a = null;
//GC.Collect();
//GC.WaitForPendingFinalizers();
}
private void button2_Click(object sender, EventArgs e)
{
a = null;
//GC.Collect();
}
private void button3_Click(object sender, EventArgs e)
{
if (a != null)
{ a.Dispose(); }
}
private void button4_Click(object sender, EventArgs e)
{
GC.Collect();
}
private void button5_Click(object sender, EventArgs e)
{
//立即释放a
a = null;
GC.Collect();
}
private void button6_Click(object sender, EventArgs e)
{
if (a != null)
{
//清空数组,等待下一次GC.Collect()时释放
a.ClearAry();
}
}
}
///
/// 参照msdn改写
/// http://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&l=EN-US&k=k(SYSTEM.IDISPOSABLE);k(TargetFrameworkMoniker-%22.NETFRAMEWORK%2cVERSION%3dV3.5%22);k(DevLang-CSHARP)&rd=true
///
public class AA:IDisposable
{
private bool disposed = false;
private FileStream fs;
private byte[] btary;
public AA(string filepath)
{
btary = new byte[10000000];
//数组全部置零
Array.Clear(btary, 0, btary.Length);
fs = new FileStream(filepath,FileMode.Open);
}
public void ClearAry()
{
btary = null;
//GC.Collect();
}
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
//若程序中显示调用该类对象的Dispose()
//执行完下句,则不会再调用析构
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
//在此处填充代码,调用托管资源的Dispose
}
//在此处填充代码,释放非托管资源
fs.Dispose();
disposed = true;
}
}
~AA()
{
Dispose(false);
//MessageBox.Show("析构了~");
}
}
}
using System;
using System.ComponentModel;
// The following example demonstrates how to create
// a resource class that implements the IDisposable interface
// and the IDisposable.Dispose method.
public class DisposeExample
{
// A base class that implements IDisposable.
// By implementing IDisposable, you are announcing that
// instances of this type allocate scarce resources.
public class MyResource: IDisposable
{
// Pointer to an external unmanaged resource.
private IntPtr handle;
// Other managed resource this class uses.
private Component component = new Component();
// Track whether Dispose has been called.
private bool disposed = false;
// The class constructor.
public MyResource(IntPtr handle)
{
this.handle = handle;
}
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
private void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources.
component.Dispose();
}
// Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.
CloseHandle(handle);
handle = IntPtr.Zero;
// Note disposing has been done.
disposed = true;
}
}
// Use interop to call the method necessary
// to clean up the unmanaged resource.
[System.Runtime.InteropServices.DllImport("Kernel32")]
private extern static Boolean CloseHandle(IntPtr handle);
// Use C# destructor syntax for finalization code.
// This destructor will run only if the Dispose method
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide destructors in types derived from this class.
~MyResource()
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
}
public static void Main()
{
// Insert code here to create
// and use the MyResource object.
}
}