托管资源与非托管资源

“非托管资源”指的是不受.net垃圾回收器控制的资源。比如打开一个数据库连接,所访问的数据库资源来源于服务器而不受.net控制。或者是客户机上其他非.net资源,资源的提供者不是通过托管代码编写的。

这就是为什么对于数据库连接,需要写在一个using中

using (var connection = new SqlConnection("connection_string_here"))

{

connection.open();

//..do something...

connection.close();

}

这样using执行完后会调用连接对象的.Dispose()方法,确保所有非托管资源被清除。

以上代码等价于

var connection = new SqlConnection("connection_string_here")

try

{

connection.open();

//..do something...

connection.close();

}

finally

{

if (connection != null) ((IDisposable)connection).Dispose();

}

常见的非托管资源有:文件句柄、数据流、固定内存、COM 对象、数据库连接、网络连接

这些非托管资源如果没有显式地清理他们,将会造成数据泄露和资源占用。

对于托管资源,则无需担心其何时被销毁,当一个对象实例没有被任何变量引用时,系统会自动对其进行垃圾回收

释放非托管资源方法

下面用一个例子来介绍一下.NET非托管资源回收方法

将包含非托管对象的类继承IDisposable接口,IDisposable接口要求实现Dispose方法

Stream抽象类本身也继承了IDispose接口,如果是要创建一个自定义的Stream类,则它会继承父类的所有接口,包括IDispose;在以下编写的类WrappingStream中,定义了一个Stream类型的成员m_streamBase,用于接收非托管资源,

有两个作用:

1.如果外部的传入的非托管资源已释放,WrappingStream内部的流不会释放,保证BinaryReader能够完全控制这个流。

2.由于WrappingStream继承IDispose,在使用该对象时,包在using中,当using执行完后释放内部的流时,不会导致外部的流也释放,保证外部的流供其他程序正常使用

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.IO;

namespace MyStreamClass

{

///

/// A that wraps another stream. The major feature of is that it does not dispose the

/// underlying stream when it is disposed; this is useful when using classes such as and

/// that take ownership of the stream passed to their constructors.

///

public class WrappingStream : Stream

{

///

/// Initializes a new instance of the class.

///

/// The wrapped stream.

public WrappingStream(Stream streamBase)

{

m_streamBase = streamBase ?? throw new ArgumentNullException("streamBase");

}

///

/// Gets a value indicating whether the current stream supports reading.

///

/// true if the stream supports reading; otherwise, false.

public override bool CanRead

{

get { return m_streamBase == null ? false : m_streamBase.CanRead; }

}

///

/// Gets a value indicating whether the current stream supports seeking.

///

/// true if the stream supports seeking; otherwise, false.

public override bool CanSeek

{

get { return m_streamBase == null ? false : m_streamBase.CanSeek; }

}

///

/// Gets a value indicating whether the current stream supports writing.

///

/// true if the stream supports writing; otherwise, false.

public override bool CanWrite

{

get { return m_streamBase == null ? false : m_streamBase.CanWrite; }

}

///

/// Gets the length in bytes of the stream.

///

public override long Length

{

get { ThrowIfDisposed(); return m_streamBase.Length; }

}

///

/// Gets or sets the position within the current stream.

///

public override long Position

{

get { ThrowIfDisposed(); return m_streamBase.Position; }

set { ThrowIfDisposed(); m_streamBase.Position = value; }

}

///

/// Begins an asynchronous read operation.

///

public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)

{

ThrowIfDisposed();

return m_streamBase.BeginRead(buffer, offset, count, callback, state);

}

///

/// Begins an asynchronous write operation.

///

public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)

{

ThrowIfDisposed();

return m_streamBase.BeginWrite(buffer, offset, count, callback, state);

}

///

/// Waits for the pending asynchronous read to complete.

///

public override int EndRead(IAsyncResult asyncResult)

{

ThrowIfDisposed();

return m_streamBase.EndRead(asyncResult);

}

///

/// Ends an asynchronous write operation.

///

public override void EndWrite(IAsyncResult asyncResult)

{

ThrowIfDisposed();

m_streamBase.EndWrite(asyncResult);

}

///

/// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.

///

public override void Flush()

{

ThrowIfDisposed();

m_streamBase.Flush();

}

///

/// Reads a sequence of bytes from the current stream and advances the position

/// within the stream by the number of bytes read.

///

public override int Read(byte[] buffer, int offset, int count)

{

ThrowIfDisposed();

return m_streamBase.Read(buffer, offset, count);

}

///

/// Reads a byte from the stream and advances the position within the stream by one byte, or returns -1 if at the end of the stream.

///

public override int ReadByte()

{

ThrowIfDisposed();

return m_streamBase.ReadByte();

}

///

/// Sets the position within the current stream.

///

/// A byte offset relative to the parameter.

/// A value of type indicating the reference point used to obtain the new position.

/// The new position within the current stream.

public override long Seek(long offset, SeekOrigin origin)

{

ThrowIfDisposed();

return m_streamBase.Seek(offset, origin);

}

///

/// Sets the length of the current stream.

///

/// The desired length of the current stream in bytes.

public override void SetLength(long value)

{

ThrowIfDisposed();

m_streamBase.SetLength(value);

}

///

/// Writes a sequence of bytes to the current stream and advances the current position

/// within this stream by the number of bytes written.

///

public override void Write(byte[] buffer, int offset, int count)

{

ThrowIfDisposed();

m_streamBase.Write(buffer, offset, count);

}

///

/// Writes a byte to the current position in the stream and advances the position within the stream by one byte.

///

public override void WriteByte(byte value)

{

ThrowIfDisposed();

m_streamBase.WriteByte(value);

}

///

/// Gets the wrapped stream.

///

/// The wrapped stream.

protected Stream WrappedStream

{

get { return m_streamBase; }

}

///

/// Releases the unmanaged resources used by the and optionally releases the managed resources.

///

/// true to release both managed and unmanaged resources; false to release only unmanaged resources.

protected override void Dispose(bool disposing)

{

// doesn't close the base stream, but just prevents access to it through this WrappingStream

if (disposing)

m_streamBase = null;

base.Dispose(disposing);

}

private void ThrowIfDisposed()

{

// throws an ObjectDisposedException if this object has been disposed

if (m_streamBase == null)

throw new ObjectDisposedException(GetType().Name);

}

Stream m_streamBase;

}

}

在使用这个类时,将Stream作为一个方法传入参数传给WrapStream并实例化

private void Create(Stream streamSource)

{

Random rnd = new Random();

var connections = new int[] { (int)ConnectionType.Tab, (int)ConnectionType.Blank };

png = null;

imageSource = null;

var uri = new Uri(destFileName);

//We do this to avoid memory leaks

using (WrappingStream wrapper = new WrappingStream(streamSource))

using (BinaryReader reader = new BinaryReader(wrapper))

{

imageSource = new BitmapImage();

imageSource.BeginInit();

imageSource.CacheOption = BitmapCacheOption.OnLoad;

imageSource.StreamSource = reader.BaseStream; // streamSource;

imageSource.EndInit();

imageSource.Freeze();

}

imgShowImage.Source = imageSource;

scvImage.Visibility = Visibility.Hidden;

cnvPuzzle.Visibility = Visibility.Visible;

var angles = new int[] { 0, 90, 180, 270 };

int index = 0;

for (var y = 0; y < rows; y++)

{

for (var x = 0; x < columns; x++)

{

if (x != 1000)

{

int upperConnection = (int)ConnectionType.None;

int rightConnection = (int)ConnectionType.None;

int bottomConnection = (int)ConnectionType.None;

int leftConnection = (int)ConnectionType.None;

if (y != 0)

upperConnection = -1 * pieces[(y - 1) * columns + x].BottomConnection;

if (x != columns - 1)

rightConnection = connections[rnd.Next(2)];

if (y != rows - 1)

bottomConnection = connections[rnd.Next(2)];

if (x != 0)

leftConnection = -1 * pieces[y * columns + x - 1].RightConnection;

int angle = 0;

var piece = new Piece(imageSource, x, y, 0.1, 0.1, (int)upperConnection, (int)rightConnection, (int)bottomConnection, (int)leftConnection, false, index, scale);

piece.SetValue(Canvas.ZIndexProperty, 1000 + x * rows + y);

piece.MouseLeftButtonUp += new MouseButtonEventHandler(Piece_MouseLeftButtonUp);

piece.MouseRightButtonUp += new MouseButtonEventHandler(Piece_MouseRightButtonUp);

piece.Rotate(piece, angle);

var shadowPiece = new Piece(imageSource, x, y, 0.1, 0.1, (int)upperConnection, (int)rightConnection, (int)bottomConnection, (int)leftConnection, true, shadowPieces.Count(), scale);

shadowPiece.SetValue(Canvas.ZIndexProperty, x * rows + y);

shadowPiece.Rotate(piece, angle);

pieces.Add(piece);

shadowPieces.Add(shadowPiece);

index++;

}

}

}

var tt = new TranslateTransform() { X = 20, Y = 20 };

foreach (var p in pieces)

{

Random random = new Random();

int i = random.Next(0, pnlPickUp.Children.Count);

p.ScaleTransform.ScaleX = 1.0;

p.ScaleTransform.ScaleY = 1.0;

p.RenderTransform = tt;

p.X = -1;

p.Y = -1;

p.IsSelected = false;

pnlPickUp.Children.Insert(i, p);

double angle = angles[rnd.Next(0, 4)];

p.Rotate(p, angle);

shadowPieces[p.Index].Rotate(p, angle);

}

rectSelection.SetValue(Canvas.ZIndexProperty, 5000);

rectSelection.StrokeDashArray = new DoubleCollection(new double[] { 4, 4, 4, 4 });

cnvPuzzle.Children.Add(rectSelection);

}

这是加了WrappingStream垃圾回收的效果

这是未加WrappingStream垃圾回收的效果,