托管资源与非托管资源
“非托管资源”指的是不受.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
{
/// <summary>
/// A <see cref="Stream"/> that wraps another stream. The major feature of <see cref="WrappingStream"/> is that it does not dispose the
/// underlying stream when it is disposed; this is useful when using classes such as <see cref="BinaryReader"/> and
/// <see cref="System.Security.Cryptography.CryptoStream"/> that take ownership of the stream passed to their constructors.
/// </summary>
public class WrappingStream : Stream
{
/// <summary>
/// Initializes a new instance of the <see cref="WrappingStream"/> class.
/// </summary>
/// <param name="streamBase">The wrapped stream.</param>
public WrappingStream(Stream streamBase)
{
m_streamBase = streamBase ?? throw new ArgumentNullException("streamBase");
}
/// <summary>
/// Gets a value indicating whether the current stream supports reading.
/// </summary>
/// <returns><c>true</c> if the stream supports reading; otherwise, <c>false</c>.</returns>
public override bool CanRead
{
get { return m_streamBase == null ? false : m_streamBase.CanRead; }
}
/// <summary>
/// Gets a value indicating whether the current stream supports seeking.
/// </summary>
/// <returns><c>true</c> if the stream supports seeking; otherwise, <c>false</c>.</returns>
public override bool CanSeek
{
get { return m_streamBase == null ? false : m_streamBase.CanSeek; }
}
/// <summary>
/// Gets a value indicating whether the current stream supports writing.
/// </summary>
/// <returns><c>true</c> if the stream supports writing; otherwise, <c>false</c>.</returns>
public override bool CanWrite
{
get { return m_streamBase == null ? false : m_streamBase.CanWrite; }
}
/// <summary>
/// Gets the length in bytes of the stream.
/// </summary>
public override long Length
{
get { ThrowIfDisposed(); return m_streamBase.Length; }
}
/// <summary>
/// Gets or sets the position within the current stream.
/// </summary>
public override long Position
{
get { ThrowIfDisposed(); return m_streamBase.Position; }
set { ThrowIfDisposed(); m_streamBase.Position = value; }
}
/// <summary>
/// Begins an asynchronous read operation.
/// </summary>
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
{
ThrowIfDisposed();
return m_streamBase.BeginRead(buffer, offset, count, callback, state);
}
/// <summary>
/// Begins an asynchronous write operation.
/// </summary>
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
{
ThrowIfDisposed();
return m_streamBase.BeginWrite(buffer, offset, count, callback, state);
}
/// <summary>
/// Waits for the pending asynchronous read to complete.
/// </summary>
public override int EndRead(IAsyncResult asyncResult)
{
ThrowIfDisposed();
return m_streamBase.EndRead(asyncResult);
}
/// <summary>
/// Ends an asynchronous write operation.
/// </summary>
public override void EndWrite(IAsyncResult asyncResult)
{
ThrowIfDisposed();
m_streamBase.EndWrite(asyncResult);
}
/// <summary>
/// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.
/// </summary>
public override void Flush()
{
ThrowIfDisposed();
m_streamBase.Flush();
}
/// <summary>
/// Reads a sequence of bytes from the current stream and advances the position
/// within the stream by the number of bytes read.
/// </summary>
public override int Read(byte[] buffer, int offset, int count)
{
ThrowIfDisposed();
return m_streamBase.Read(buffer, offset, count);
}
/// <summary>
/// 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.
/// </summary>
public override int ReadByte()
{
ThrowIfDisposed();
return m_streamBase.ReadByte();
}
/// <summary>
/// Sets the position within the current stream.
/// </summary>
/// <param name="offset">A byte offset relative to the <paramref name="origin"/> parameter.</param>
/// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"/> indicating the reference point used to obtain the new position.</param>
/// <returns>The new position within the current stream.</returns>
public override long Seek(long offset, SeekOrigin origin)
{
ThrowIfDisposed();
return m_streamBase.Seek(offset, origin);
}
/// <summary>
/// Sets the length of the current stream.
/// </summary>
/// <param name="value">The desired length of the current stream in bytes.</param>
public override void SetLength(long value)
{
ThrowIfDisposed();
m_streamBase.SetLength(value);
}
/// <summary>
/// Writes a sequence of bytes to the current stream and advances the current position
/// within this stream by the number of bytes written.
/// </summary>
public override void Write(byte[] buffer, int offset, int count)
{
ThrowIfDisposed();
m_streamBase.Write(buffer, offset, count);
}
/// <summary>
/// Writes a byte to the current position in the stream and advances the position within the stream by one byte.
/// </summary>
public override void WriteByte(byte value)
{
ThrowIfDisposed();
m_streamBase.WriteByte(value);
}
/// <summary>
/// Gets the wrapped stream.
/// </summary>
/// <value>The wrapped stream.</value>
protected Stream WrappedStream
{
get { return m_streamBase; }
}
/// <summary>
/// Releases the unmanaged resources used by the <see cref="WrappingStream"/> and optionally releases the managed resources.
/// </summary>
/// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
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垃圾回收的效果,
|