http://blog.csdn.net/courageously/article/details/5730095
Marshal类支持从托管内存空间复制数据到非托管内存空间,或是从非托管内存空间到托管内存空间。如果你研究在线的MSDN文档库,你会看到在桌面.NET框架下这个类支持的分配非托管内存空间的方法和其他的一些与COM对象共同工作的方法。没有任何内存空间管理和COM支持方法在.NET精简框架的Marshal实现中出现。表4.5总结了Marshal类的被.NET精简框架支持的成员:13方法名(有一个或多个重载版本)和1个只读域。
表4.5 Marshal类中.NET精简框架支持的成员
Marshal 成员 | 描述 |
在托管和非托管间复制 | |
Copy | 在托管和非托管内存空间之间复制值类型数组。支持CLI整型,包括64位整型。支持单精度和双精度浮点数。有14个重载的方法(7个用来复制到托管内存空间;7个用来复制到非托管内存空间) |
复制到非托管内存空间 | |
StructureToPtr | 复制托管对象到非托管内存空间 |
WriteByte | 写入一个字节(byte)到非托管内存空间 |
WriteInt16 | 写入两个字节到非托管内存空间 |
WriteInt32 | 写入4个字节到非托管内存空间 |
复制到托管内存空间 | |
PtrToStringUni | 在非托管内存空间中创建一个托管的字符串 |
PtrToStructure | 在非托管内存空间中创建一个对象 |
ReadByte | 从非托管内存空间中读取一个字节 |
ReadInt16 | 从非托管内存空间中读取两个字节 |
ReadInt32 | 从非托管内存空间中读取四个字节 |
信息的 | |
IsComObject | 如果是硬编码返回False |
SizeOf | 查询一个对象实体的非托管大小。用来设置一些Win32函数调用的结构体大小的域值。 |
GetLastWin32Error | 调用GetLastError函数来取回Win32错误码 |
SystemDefaultCharSize | 在默认的字符集中,字符大小的只读的域。(在.NET精简框架中返回2。)为了可移植性。 |
Marshal类的一些方法允许改写非托管的缓存,于是你就能够将它们作为参数传递到非托管函数中。这个类的另外一些方法可以让你从非托管缓存中读取值并写入托管数据对象中。从缓存中改写和读取都是重要的,因为Win32 API(连同许多其它的基于C的API)为从一个调用者到一个被调函数的通信提供了使用缓存的扩展。
这个表不包括许多用来分配非托管内存的函数。下面的内存分配函数在MSDN库中有所说明,并且内建在桌面.NET框架中,但是他们不被.NET精简框架所支持。
ü AllocHGlobal
ü FreeHGlobal
ü AllocCoTaskMem
ü FreeCoTaskMem
在你从托管内存中读取或写入之前,你需要获得一些非托管内存空间。在深入到Marshal类的内存复制方法中之前,我们需要看一看一个.NET精简框架程序员如何处理内存分配。
分配非托管内存空间
我们称之为“非托管”内存是因为运行时的垃圾收集器不会管理内存。而你必须管理你分配的内存,这就意味着当你不再使用它的时候,需要释放这些内存。没有释放内存空间会导致内存泄漏。当内存的泄露到一定程度的时候,你的程序或操作系统本身可能会崩溃。你必须小心释放任何你所分配的内存。(关于分配内存和相关的清理的Win32函数的总结,请看附件D。)
你已经具有了释放自己分配的内存的责任心,接下来需要训练你记住一些准则来正确的做这些工作。当我们编写分配内存的代码时,我们总是在写过分配内存的代码之后立即编写释放内存的代码。然后我们要检查以确定是否释放了每个可能的代码路径分配的内存,不仅仅是成功的情况,更重要的是也包括当错误条件存在时的处理。这些努力是要避免内存的泄漏,即一个Win32 API的主要问题(并且是.NET的出现如此重要的原因,托管代码可以自动完成这些工作)。