VB.NET 内存指针和非托管内存的应用
介绍
Visual Basic 从来不像在C或C++里一样灵活的操纵指针和原始内存。然而利用.NET框架中的structures 和 classes,可以做许多类似的事情。它们包括 IntPtr, Marshal 以及 GCHandle。 这些structures(结构) 和classes(类) 允许你在托管和非托管环境中进行交互。本文中将向您展示如何使用这些structures 和 classes 去完成指针和内存的操作。
关于 IntPtr 结构
IntPtr 结构的行为像一个整型指针以便能应用到专门的平台。这个结构可以应用到支持或不支持指针的语言中。 .NET 文件 IO 类使用这个 结构扩展操作文件句柄。这个 IntPtr 结构形如整型指针的行为,但是它没有写或读相应位置内存的能力。这时你就需要System.Runtime.InteropServices 命名空间中的 Marshal 类。
关于 Marshal 类
这个类提供了全部分配非托管内存、拷贝非托管内存块,以及转换托管到非托管类型的方法。要保证你的代码导入了 System.Runtime.InteropServices 。
关于 GCHandle 结构
GCHandle 结构提供了从非托管内存中处理托管对象的方法。在非托管代码使用它时,可以控制垃圾碎片收集。
整数值的(读) 与 (写)
在我们的第一个例子中,使用 Marshal 类在内存中储存一个整数,得到一个内存指针去指向它在内存中的位置,并存到一个 IntPtr 结构中。最终我们将使用 Marshal 类读回这个值。
这里我们声明一个IntPtr类型,并且使用Marshal类中的AllocHGlobal 共享方法从全局堆中分配一个4字节的内存,并返回它的地址,存储在 IntPtr 变量中。接下来我们使用Marshal类中的WriteInt32 方法将整数值写到内存中。
Dim ptr As IntPtr : Dim n As Integer = 123
tr = Marshal.AllocHGlobal(4) '在进程的非托管内存中划分 4 字节大小的内存空间,并返回内存的指针地址
Marshal.WriteInt32(ptr, n) '将32位有符号的整数写入划分的内存空间中
Marshal.AllocHGlobal 方法的返回值为:指向新分配的内存的指针。
用完后必须使用 Marshal.FreeHGlobal 方法释放划分的内存
用下面的方法,你可以读指定位置的内存中的数。
Dim myInt As Integer = Marshal.ReadInt32(ptr) '参数 ptr 为内存空间指针
Marshal.ReadInt32 方法的返回值为:内存空间中的数据值。
字符串的(读) 与 (写)
在这个例子中,我们写一个托管字符串到堆中,并且随后读出来。
Dim str As String = "hello world" '字符串为引用类型,所以存储在非托管堆上
Dim ptr As IntPtr = Marshal.StringToHGlobalAuto(str) '向非托管内存中复制托管内容,并转换为ANSI格式
这里,我们使用了 Marshal类 中的 StringToHGlobalAuto() 方法拷贝托管字符串到非托管内存中。将内存指针地址保存在 IntPtr 结构中。为了从指定内存位置读回字符串,我们使用 Marshal 类中的 PtrToStringAuto() 方法 。
Dim mystring As String = Marshal.PtrToStringAuto(ptr) '从存储在非托管内存中的字符串复制等数量的字符到托管内存中
结构的(读) 与 (写)
在下一个例子中,我们将看到如何使用 Marshal 类和 IntPtr 结构,进行结构的读与写。
Public Class A
Public Structure PointA
Dim x As Integer
Dim y As Integer
'Public Sub New(ByVal _x As Integer, ByVal _y As Integer)
' x = _x
' y = _y
'End Sub
End Structure
Private Sub RWMemory()
Dim myStruct As PointA '其实.net框架自带 Point 坐标抽x,y类型(这里我们用自定义的结构类)
myStruct.x = 100 : myStruct.y = 200
'通过指定的字节数,在非托管堆划分内存空间(这里的字节数是结构对象,它又包含了x,y坐标值,所以字节数就是x,y坐标)
Dim ptr As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(myStruct)) '返回内存指针地址
Marshal.StructureToPtr(myStruct, ptr, True) '将数据从托管中(堆栈)封送到非托管(托管堆)的内存块中
Marshal.PtrToStructure(ptr, myStruct.GetType) '将数据从非托管(托管堆)的内存块中封送到托管(堆栈)
End Sub
End Class
这里我们使用一个名为 PointA 的结构。这个代码,要注意,我们使用了 Marshal 类中的 SizeOf 方法,它返回结构变量的尺寸。 而StructureToPtr 接收要被写的结构变量,将数据从托管中(堆栈)封送到非托管(托管堆)的内存块中。一个IntPtr 实例将被返回,同时标明是否Marshal类应该调用。
DestroyStructure 方法,建议标记为 True,如果标记为 false 可能导致内存泄漏。最后我们使用 Marshal 类的 PtrToStructure 方法反封送结构的值,展示了两个方法很好的实现了交互式功能。
对象的(读) 与 (写)
现在我们了解了如何用 Marshal 和 IntPtr 类读写值类型。
而托管对象的处理稍微不同。需要使用 GCHandle 来读写这些对象,
下面的代码显示如何做:
Public Class Employee
Public Name As String
Public Salary As Decimal
End Class
Private Sub wp()
Dim gh As GCHandle 'GCHandle类提供用于从非托管内存访问托管对象的方法
Dim emp As New Employee
emp.Name = "John"
emp.Salary = 12345.67
gh = GCHandle.Alloc(emp) '从非托管内存中访问托管对象,Alloc 方法能指定的对象分配句柄
Dim emp2 As Employee = gh.Target '设置该句柄表示的对象
gh.Free() '释放GCHandles句柄
End Sub
这里,对于自定义的 Employee 类我们使用 GCHandle (碎片手机句柄) 类进行分配和释放内存。共享(静态)的 Alloc 方法接受对象并存储在内存中并一个 GCHandle 类的实例。
我们可以使用这个对象的Target属性指向对象的引用。我们可以使用 GCHandle 实例的 Free() 方法来销毁相应的内存。
总结
在VB.NET中使用指针和非托管操作并不是易事,然而 IntPtr ,GCHandle 结构 和 Marshal 类可以让你完成类似的事情。
| 作者 | |||
|
|||
VB.NET 内存指针和非托管内存的应用的更多相关文章
- 如何让IntPtr指向一块内存,以及托管内存与非托管内存的相互转化
IntPtr idp= IntPtr.Zero; StringBuilder idata = new StringBuilder("000000"); string idata = ...
- C# 托管内存与非托管内存之间的转换
c#有自己的内存回收机制,所以在c#中我们可以只new,不用关心怎样delete,c#使用gc来清理内存,这部分内存就是managed memory,大部分时候我们工作于c#环境中,都是在使用托管内存 ...
- C# 中托管内存与非托管内存之间的转换
c#有自己的内存回收机制,所以在c#中我们可以只new,不用关心怎样delete,c#使用gc来清理内存,这部分内存就是managed memory,大部分时候我们工作于c#环境中,都是在使用托管内存 ...
- 记一次 .NET 某智慧水厂API 非托管内存泄漏分析
一:背景 1. 讲故事 七月底的时候有位朋友在wx上找到我,说他的程序内存占用8G,托管才占用1.5G,询问剩下的内存哪里去了?截图如下: 从求助内容看,这位朋友真的太客气了,动不动就谈钱,真伤感情, ...
- 记一次 .NET 某打印服务 非托管内存泄漏分析
一:背景 1. 讲故事 前段时间有位朋友在微信上找到我,说他的程序出现了内存泄漏,能不能帮他看一下,这个问题还是比较经典的,加上好久没上非托管方面的东西了,这篇就和大家分享一下,话不多说,上 WinD ...
- [JVM教程与调优] 了解JVM 堆内存溢出以及非堆内存溢出
在上一章中我们介绍了JVM运行时参数以及jstat指令相关内容:[JVM教程与调优] 什么是JVM运行时参数?.下面我们来介绍一下jmap+MAT内存溢出. 首先我们来介绍一下下JVM的内存结构. J ...
- 记一次 .NET 某桌面奇侠游戏 非托管内存泄漏分析
一:背景 1. 讲故事 说实话,这篇dump我本来是不准备上一篇文章来解读的,但它有两点深深的感动了我. 无数次的听说用 Unity 可做游戏开发,但百闻不如一见. 游戏中有很多金庸武侠小说才有的名字 ...
- 在内存中观察CRL托管内存及GC行为
虽然看了一些书,还网络上的一些博文,不过对CRL托管内存的介绍都不是十分清楚,大部分都是一样的,如果再要了解细节就十分困难了. 所以借助winhex直接查看内存以证实书上的描述或更进一步揣摩CRL托管 ...
- Java堆内存Heap与非堆内存Non-Heap
堆(Heap)和非堆(Non-heap)内存 按照官方的说法:“Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配.堆是在 Java 虚拟机启动时创建的.”“在 ...
随机推荐
- trangleProble switch方法 java
public class trangleProblem { static int res=1; int codePart=1; int n=100; Stack<Param> stack= ...
- C++中如何split字符串(转)
#include <iostream> #include <sstream> #include <string> using namespace std; int ...
- ios ColorLUT滤镜
通过这种方格图片实现滤镜 代码: "CIFilter+ColorLUT.h" "CIFilter+ColorLUT.m" #import "CIFil ...
- CATCell <——>CATPoint
假定原先有CATCell tCell; CATVertex_var spVertex = tCell; CATPoint_var spPoint = spVertex -> GetPoint() ...
- spring注解注入:<context:component-scan>使用说明
spring从2.5版本开始支持注解注入,注解注入可以省去很多的xml配置工作.由于注解是写入java代码中的,所以注解注入会失去一定的灵活性,我们要根据需要来选择是否启用注解注入. 在XML中配置了 ...
- Mysql优化之创建高性能索引(三)
聚蔟索引 聚蔟索引并不是一种单独的索引类型,而是一种数据存储方式.Innodb的聚蔟索引在同一结构保存了B-Tree索引和数据行. 当表有聚蔟索引时,它的数据行实际上存放在索引的叶子页中.下图展示了聚 ...
- php array 排序 感悟
array 排序总体有这几个函数sort.rsort.asort.arsort.ksort.krsort.usort.uasort.uksort. 一开始我记来记去总是有点混乱,后来认真对比后终于清 ...
- Raknet实现的简单服务器与客户端的交互
1. 首先下载Raknet的源代码,我用的是4.0的,不是最新的,解压后编译DLL工程,编译完成后进入解压的根目录下,进入Lib文件夹下找到RakNet_DLL_Debug_Win32.dll, R ...
- 恶补ASP.NET基础【1】枚举和结构
有时我们希望变量提取的是一个固定集合中的值,此时就可以用枚举类型, 例: enum OpenMode : byte { 新增=, 编辑=, 查看= } class Program { static v ...
- Matlab 仿真实现TI Instaspin 的Foc 逆Clarke变换和SVPWM
一直没搞明白TI 的Instaspin的SVPWM实现原理,最后只能在Matlab里仿真看看输出波形是不是和普通的SVPWM实现输出的波形一样,用M文件实现,下面是代码: clear all; the ...