UnmanagedArray 非托管数组,可随时释放内存

由于在C# 里提供的 int[] array = new int[1000000]; 这样的数组,其内存释放很难由程序员完全控制,在申请一个大数组后,程序可能会变得很慢。


/// <summary>
///元素类型为sbyte, byte, char, short, ushort, int, uint, long, ulong, float, double, decimal, bool 或其它struct的非托管数组
/// 可随时释放内存
/// </summary>
/// <typeparam name="T">sbyte, byte, char, short, ushort, int, uint, long, ulong, float, double, decimal, bool或其它struct, 不能使用enum类型作为T</typeparam>
public class UnmanagedArray<T> : UnmanagedArrayBase where T : struct
{
    /// <summary>
    /// 元素类型为sbyte, byte, char, short, ushort, int, uint, long, ulong, float, double, decimal, bool 或其它struct的非托管数组
    /// </summary>
    /// <param name="count"></param>
    [MethodImpl(MethodImplOptions.Synchronized)]
    public UnmanagedArray(int count) : base(count, Marshal.SizeOf(typeof(T)))
    {
    }
    /// <summary>
    /// 获取或设置索引为<paramref name="index"/>的元素
    /// </summary>
    /// <param name="index"></param>
    /// <returns></returns>
    public T this[int index]
    {
        get
        {
            if (index < 0 || index >= Count)
            {
                throw new IndexOutOfRangeException("index of UnmanagedArray is out of range");
            }
            var pItem = Header + (index * _elementSize);
            T rslt = Marshal.PtrToStructure<T>(pItem);
            return rslt;
        }
        set
        {
            if (index < 0 || index >= Count)
            {
                throw new IndexOutOfRangeException("index of UnmanagedArray is out of range");
            }
            var pItem = Header + (index * _elementSize);
            Marshal.StructureToPtr<T>(value, pItem, true);
        }
    }
    /// <summary>
    /// 按索引顺序依次获取各个元素
    /// </summary>
    /// <returns></returns>
    public IEnumerable<T> GetElements()
    {
        if (!this._disposed)
        {
            for (int i = 0; i < Count; i++)
            {
                yield return this[i];
            }
        }
    }
}

public abstract class UnmanagedArrayBase : IDisposable
{
    /// <summary>
    /// 数组指针
    /// </summary>
    public IntPtr Header { get; private set; }
    /// <summary>
    /// 元素数目
    /// </summary>
    public int Count { get; private set; }
    /// <summary>
    /// 申请到的字节数
    /// </summary>
    public int ByteLength
    {
        get { return this.Count * this._elementSize; }
    }
    /// <summary>
    /// 单个元素的字节数
    /// </summary>
    protected int _elementSize;
    protected static readonly List<IDisposable> _allocatedArrays = new List<IDisposable>();

    /// <summary>
    /// 非托管数组
    /// </summary>
    /// <param name="elementCount">元素数目</param>
    /// <param name="elementSize">单个元素的字节数</param>
    [MethodImpl(MethodImplOptions.Synchronized)]
    protected UnmanagedArrayBase(int elementCount, int elementSize)
    {
        Count = elementCount;
        _elementSize = elementSize;

        int memSize = elementCount * elementSize;
        Header = Marshal.AllocHGlobal(memSize);
        _allocatedArrays.Add(this);
    }
    /// <summary>
    /// 立即释放所有<see cref="UnmanagedArray"/>
    /// </summary>
    [MethodImpl(MethodImplOptions.Synchronized)]
    public static void FreeAll()
    {
        foreach (var item in _allocatedArrays)
        {
            item.Dispose();
        }
        _allocatedArrays.Clear();
    }
    ~UnmanagedArrayBase()
    {
        Dispose();
    }
    #region IDisposable
    protected bool _disposed;

    protected void Dispose(bool disposiing)
    {
        if (_disposed)
        {
            return;
        }
        if (disposiing)
        {
            // 托管类型清理
        }
        IntPtr ptr = this.Header;
        if (ptr != IntPtr.Zero)
        {
            Count = 0;
            Header = IntPtr.Zero;
            Marshal.FreeHGlobal(ptr);
        }
        _disposed = true;
    }
    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    #endregion
}

public static class UnmanagedArrayExtend
{
    /// <summary>
    /// 获取非托管数组的第一个元素的地址
    /// </summary>
    /// <param name="array"></param>
    /// <returns></returns>
    public static unsafe void* FirstElement(this UnmanagedArrayBase array)
    {
        var header = (void*)array.Header;
        return header;
    }

    /// <summary>
    /// 获取非托管数组的最后一个元素的地址再向后一个单位的地址
    /// </summary>
    /// <param name="array"></param>
    /// <returns></returns>
    public static unsafe void* TailAddress(this UnmanagedArrayBase array)
    {
        var tail = (void*)(array.Header + array.ByteLength);
        return tail;
    }
}
posted @ 2024-05-25 15:20  wesson2019  阅读(30)  评论(0编辑  收藏  举报