C#+无unsafe的非托管大数组(large unmanaged array in c# without 'unsafe' keyword)

C#+无unsafe的非托管大数组(large unmanaged array in c# without ‘unsafe‘ keyword)

+BIT祝威+悄悄在此留下版了个权的信息说:

C#申请一个大数组(Use a large array in C#)

在C#里,有时候我需要能够申请一个很大的数组、使用之、然后立即释放其占用的内存。

Sometimes I need to allocate a large array, use it and then release its memory space immediately.

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

If I use something like  int[] array = new int[1000000]; , it will be difficult to release its memory space by programmer and the app probably runs slower and slower.

特别是在C#+OpenGL编程中,我在使用VAO/VBO时十分需要设计一个非托管的数组,比如在glBufferData时我希望可以使用下面的glBufferData:

Specially in C#+OpenGL routines when I‘m using VAO/VBO, I need an unmanaged array for glBufferData:

 1         /// <summary>
 2         /// 设置当前VBO的数据。
 3         /// </summary>
 4         /// <param name="target"></param>
 5         /// <param name="data"></param>
 6         /// <param name="usage"></param>
 7         public static void glBufferData(uint target, UnmanagedArrayBase data, uint usage)
 8         {
 9             GetDelegateFor<glBufferData>()((uint)target,
10                 data.ByteLength, // 使用非托管数组
11                 data.Header, // 使用非托管数组
12                 (uint)usage);
13         }
14         // ...
15         // glBufferData的声明
16         private delegate void glBufferData(uint target, int size, IntPtr data, uint usage);

而在指定VBO的数据时,可能是float、vec3等等类型:

And the content in VBO can be float, vec3 and any other structs.

 1         /// <summary>
 2         /// 金字塔的posotion array.
 3         /// </summary>
 4         static vec3[] positions = new vec3[]
 5         {
 6             new vec3(0.0f, 1.0f, 0.0f),
 7             new vec3(-1.0f, -1.0f, 1.0f),
 8             // ...
 9             new vec3(-1.0f, -1.0f, 1.0f),
10         };
11 //  Create a vertex buffer for the vertex data.
12             {
13                 uint[] ids = new uint[1];
14                 GL.GenBuffers(1, ids);
15                 GL.BindBuffer(GL.GL_ARRAY_BUFFER, ids[0]);
16                 // 使用vec3作为泛型的非托管数组的参数
17                 UnmanagedArray<vec3> positionArray = new UnmanagedArray<vec3>(positions.Length);
18                 for (int i = 0; i < positions.Length; i++)
19                 {
20                     // 使用this[i]这样的索引方式来读写非托管数组的元素
21                     positionArray[i] = positions[i];
22                 }
23                 GL.BufferData(BufferDataTarget.ArrayBuffer, positionArray, BufferDataUsage.StaticDraw);
24                 GL.VertexAttribPointer(positionLocation, 3, GL.GL_FLOAT, false, 0, IntPtr.Zero);
25                 GL.EnableVertexAttribArray(positionLocation);
26             }

+BIT祝威+悄悄在此留下版了个权的信息说:

UnmanagedArray<T>

所以我设计了这样一个非托管的数组类型:无unsafe,可接收任何struct类型作为泛型参数,可随时释放内存。

So I designed this UnmangedArray<T> : no ‘unsafe‘ keyword, takes any struct as generic parameter, can be released anytime you want.

  1     /// <summary>
  2     /// 元素类型为sbyte, byte, char, short, ushort, int, uint, long, ulong, float, double, decimal, bool或其它struct的非托管数组。
  3     /// <para>不能使用enum类型作为T。</para>
  4     /// </summary>
  5     /// <typeparam name="T">sbyte, byte, char, short, ushort, int, uint, long, ulong, float, double, decimal, bool或其它struct, 不能使用enum类型作为T。</typeparam>
  6     public class UnmanagedArray<T> : UnmanagedArrayBase where T : struct
  7     {
  8
  9         /// <summary>
 10         ///元素类型为sbyte, byte, char, short, ushort, int, uint, long, ulong, float, double, decimal, bool或其它struct的非托管数组。
 11         /// </summary>
 12         /// <param name="count"></param>
 13         [MethodImpl(MethodImplOptions.Synchronized)]
 14         public UnmanagedArray(int count)
 15             : base(count, Marshal.SizeOf(typeof(T)))
 16         {
 17         }
 18
 19         /// <summary>
 20         /// 获取或设置索引为<paramref name="index"/>的元素。
 21         /// </summary>
 22         /// <param name="index"></param>
 23         /// <returns></returns>
 24         public T this[int index]
 25         {
 26             get
 27             {
 28                 if (index < 0 || index >= this.Count)
 29                     throw new IndexOutOfRangeException("index of UnmanagedArray is out of range");
 30
 31                 var pItem = this.Header + (index * elementSize);
 32                 //var obj = Marshal.PtrToStructure(pItem, typeof(T));
 33                 //T result = (T)obj;
 34                 T result = Marshal.PtrToStructure<T>(pItem);// works in .net 4.5.1
 35                 return result;
 36             }
 37             set
 38             {
 39                 if (index < 0 || index >= this.Count)
 40                     throw new IndexOutOfRangeException("index of UnmanagedArray is out of range");
 41
 42                 var pItem = this.Header + (index * elementSize);
 43                 //Marshal.StructureToPtr(value, pItem, true);
 44                 Marshal.StructureToPtr<T>(value, pItem, true);// works in .net 4.5.1
 45             }
 46         }
 47
 48         /// <summary>
 49         /// 按索引顺序依次获取各个元素。
 50         /// </summary>
 51         /// <returns></returns>
 52         public IEnumerable<T> GetElements()
 53         {
 54             if (!this.disposed)
 55             {
 56                 for (int i = 0; i < this.Count; i++)
 57                 {
 58                     yield return this[i];
 59                 }
 60             }
 61         }
 62     }
 63
 64     /// <summary>
 65     /// 非托管数组的基类。
 66     /// </summary>
 67     public abstract class UnmanagedArrayBase : IDisposable
 68     {
 69
 70         /// <summary>
 71         /// 数组指针。
 72         /// </summary>
 73         public IntPtr Header { get; private set; }
 74
 75         /// <summary>
 76         /// 元素数目。
 77         /// </summary>
 78         public int Count { get; private set; }
 79
 80         /// <summary>
 81         /// 单个元素的字节数。
 82         /// </summary>
 83         protected int elementSize;
 84
 85         /// <summary>
 86         /// 申请到的字节数。(元素数目 * 单个元素的字节数)。
 87         /// </summary>
 88         public int ByteLength
 89         {
 90             get { return this.Count * this.elementSize; }
 91         }
 92
 93
 94         /// <summary>
 95         /// 非托管数组。
 96         /// </summary>
 97         /// <param name="elementCount">元素数目。</param>
 98         /// <param name="elementSize">单个元素的字节数。</param>
 99         [MethodImpl(MethodImplOptions.Synchronized)]
100         protected UnmanagedArrayBase(int elementCount, int elementSize)
101         {
102             this.Count = elementCount;
103             this.elementSize = elementSize;
104
105             int memSize = elementCount * elementSize;
106             this.Header = Marshal.AllocHGlobal(memSize);
107
108             allocatedArrays.Add(this);
109         }
110
111         private static readonly List<IDisposable> allocatedArrays = new List<IDisposable>();
112
113         /// <summary>
114         /// 立即释放所有<see cref="UnmanagedArray"/>。
115         /// </summary>
116         [MethodImpl(MethodImplOptions.Synchronized)]
117         public static void FreeAll()
118         {
119             foreach (var item in allocatedArrays)
120             {
121                 item.Dispose();
122             }
123             allocatedArrays.Clear();
124         }
125
126         ~UnmanagedArrayBase()
127         {
128             Dispose();
129         }
130
131         #region IDisposable Members
132
133         /// <summary>
134         /// Internal variable which checks if Dispose has already been called
135         /// </summary>
136         protected Boolean disposed;
137
138         /// <summary>
139         /// Releases unmanaged and - optionally - managed resources
140         /// </summary>
141         /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
142         protected void Dispose(Boolean disposing)
143         {
144             if (disposed)
145             {
146                 return;
147             }
148
149             if (disposing)
150             {
151                 //Managed cleanup code here, while managed refs still valid
152             }
153             //Unmanaged cleanup code here
154             IntPtr ptr = this.Header;
155
156             if (ptr != IntPtr.Zero)
157             {
158                 this.Count = 0;
159                 this.Header = IntPtr.Zero;
160                 Marshal.FreeHGlobal(ptr);
161             }
162
163             disposed = true;
164         }
165
166         /// <summary>
167         /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
168         /// </summary>
169         public void Dispose()
170         {
171             this.Dispose(true);
172             GC.SuppressFinalize(this);
173         }
174
175         #endregion
176
177     }

UnmanagedArray

+BIT祝威+悄悄在此留下版了个权的信息说:

如何使用(How to use)

UnmanagedArray<T>使用方式十分简单,就像一个普通的数组一样:

Using UnamangedAray<T> is just like a normal array(int[], vec3[], etc.):

 1         internal static void TypicalScene()
 2         {
 3             const int count = 100;
 4
 5             // 测试float类型
 6             var floatArray = new UnmanagedArray<float>(count);
 7             for (int i = 0; i < count; i++)
 8             {
 9                 floatArray[i] = i;
10             }
11             for (int i = 0; i < count; i++)
12             {
13                 var item = floatArray[i];
14                 if (item != i)
15                 { throw new Exception(); }
16             }
17
18             // 测试int类型
19             var intArray = new UnmanagedArray<int>(count);
20             for (int i = 0; i < count; i++)
21             {
22                 intArray[i] = i;
23             }
24             for (int i = 0; i < count; i++)
25             {
26                 var item = intArray[i];
27                 if (item != i)
28                 { throw new Exception(); }
29             }
30
31             // 测试bool类型
32             var boolArray = new UnmanagedArray<bool>(count);
33             for (int i = 0; i < count; i++)
34             {
35                 boolArray[i] = i % 2 == 0;
36             }
37             for (int i = 0; i < count; i++)
38             {
39                 var item = boolArray[i];
40                 if (item != (i % 2 == 0))
41                 { throw new Exception(); }
42             }
43
44             // 测试vec3类型
45             var vec3Array = new UnmanagedArray<vec3>(count);
46             for (int i = 0; i < count; i++)
47             {
48                 vec3Array[i] = new vec3(i * 3 + 0, i * 3 + 1, i * 3 + 2);
49             }
50             for (int i = 0; i < count; i++)
51             {
52                 var item = vec3Array[i];
53                 var old = new vec3(i * 3 + 0, i * 3 + 1, i * 3 + 2);
54                 if (item.x != old.x || item.y != old.y || item.z != old.z)
55                 { throw new Exception(); }
56             }
57
58             // 测试foreach
59             foreach (var item in vec3Array.GetElements())
60             {
61                 Console.WriteLine(item);
62             }
63
64             // 释放此数组占用的内存,这之后就不能再使用vec3Array了。
65             vec3Array.Dispose();
66
67             // 立即释放所有非托管数组占用的内存,这之后就不能再使用上面申请的数组了。
68             UnmanagedArrayBase.FreeAll();
69         }

C#+无unsafe的非托管大数组(large unmanaged array in c# without 'unsafe' keyword)

时间: 2024-11-08 22:32:20

C#+无unsafe的非托管大数组(large unmanaged array in c# without 'unsafe' keyword)的相关文章

.NET对象的创建、垃圾回收、非托管资源的手动处理

本篇用来梳理对象的创建.垃圾的回收,以及非托管资源的手动处理. →首先运行应用程序,创建一个Windows进程. →CLR创建一块连续的虚拟地址空间,这个地址空间就是托管堆.而且,这个地址空间最初并没有对应的物理存储空间. 虚拟地址空间分成2段.一个区段是普通堆,也叫GC堆,大小小于85000字节的引用类型对象的实例被分配在这里:另一个是大对象堆,大小大于等于85000字节的引用类型对象的实例被分配在这里. 对于客户端应用程序,每个区段的大小大致是16MB:对于服务端应用程序,每个区段的大小大致

如何让IntPtr指向一块内存,以及托管内存与非托管内存的相互转化

IntPtr idp= IntPtr.Zero; StringBuilder idata = new StringBuilder("000000"); string idata ="000000"; 我这样建立的2个idata字符串,如何让idp指向他 我指向他的目的是为了传递给dll的某个函数,他需要传指针 还有我定义了一个结构如何向dll的函数传递其指针? 所有分了,解决一起结了 用GCHandle.Alloc(object obj)方法来给string分配一个

C# 托管和非托管混合编程

在非托管模块中实现你比较重要的算法,然后通过 CLR 的平台互操作,来使托管代码调用它,这样程序仍然能够正常工作,但对非托管的本地代码进行反编译,就很困难. 最直接的实现托管与非托管编程的方法就是使用C++/CLI 介绍 项目存档一直是企业的采用的做法,而是事实证明他们也是对的!对于一个程序员,这是几千men-days的工作量.为什么不开发一小段代码去重新利用那段代码,项目. 现在提供了一个渐渐的转向C#的新技术: 使用托管与非托管的混合编程.这是一个可行的方案在top-down issue(f

CSharpGL(36)通用的非托管数组排序方法

如果OpenGL要渲染半透明物体,一个方法是根据顶点到窗口的距离排序,按照从远到近的顺序依次渲染.所以本篇介绍对 UnmanagedArray<T> 进行排序的几种方法. +BIT祝威+悄悄在此留下版了个权的信息说: UnmanagedArray<T> 首先重新介绍一下非托管数组这个东西.一个 UnmanagedArray<float> 与一个 float[] 是一样的用处,只不过 UnmanagedArray<float> 是用 Marshal.Alloc

函数调用导致堆栈不对称。原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配。

原文:函数调用导致堆栈不对称.原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配. 在dllimport中加入CallingConvention参数就行了,[DllImport(PCAP_DLL, CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)] 要注意C++与NET中数据类型的对应: //c++:char * ---- c#:string //传入参数 //c++:char * ---- c#

托管和非托管转换新方法:Marshaling Library(zz) 【转】

托管和非托管转换新方法:Marshaling Library(zz) 托管和非托管转换新方法:Marshaling Library(zz) http://hi.baidu.com/superql/blog/item/38e9c8073202fcc37a8947ac.html 1.VC++2008中新增加的库:Marshaling Library 我们一起讨论一下VC++2008中引入的新库——Marshaling Library.在这个类库之前我们使用的传统方法是固定指针(pin_ptr).要使

浅谈 .NET 中的对象引用、非托管指针和托管指针

目录 前言 一.对象引用 二.值传递和引用传递 三.初识托管指针和非托管指针 四.非托管指针 1.非托管指针不能指向对象引用 2.类成员指针 五.托管指针 前言 本文主要是以 C# 为例介绍 .NET 中的三种指针类型(本文不包含对于函数指针的介绍):对象引用.非托管指针 .托管指针. 学习是一个不断深化理解的过程,借此博客,把自己关于 .NET 中指针相关的理解和大家一起讨论一下,若有表述不清楚,理解不正确之处,还请大家批评指正. 开始话题之前,我们不妨先对一些概念作出定义. 变量:给存储单元

[.net 面向对象程序设计进阶] (8) 托管与非托管

本节导读:虽然在.NET编程过程中,绝大多数内存垃圾回收由CLR(公共语言运行时)自动回收,但也有很多需要我们编码回收.掌握托管与非托管的基本知识,可以有效避免某些情况下导致的程序异常. 1.什么是托管与非托管? 托管资源:一般是指被CLR(公共语言运行时)控制的内存资源,这些资源由CLR来管理.可以认为是.net 类库中的资源. 非托管资源:不受CLR控制和管理的资源. 对于托管资源,GC负责垃圾回收.对于非托管资源,GC可以跟踪非托管资源的生存期,但是不知道如何释放它,这时候就要人工进行释放

在VS2010上使用C#调用非托管C++生成的DLL文件

背景 在项目过程中,有时候你需要调用非C#编写的DLL文件,尤其在使用一些第三方通讯组件的时候,通过C#来开发应用软件时,就需要利用DllImport特性进行方法调用.本篇文章将引导你快速理解这个调用的过程. 步骤 1. 创建一个CSharpInvokeCPP的解决方案: 2. 创建一个C++的动态库项目: 3. 在应用程序设置中,选择“DLL”,其他按照默认选项: 最后点击完成,得到如图所示项目: 我们可以看到这里有一些文件,其中dllmain.cpp作为定义DLL应用程序的入口点,它的作用跟