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 虚拟机启动时创建的.”“在 ...
随机推荐
- 80端口被NT kernel & System 占用pid= 4的解决方法
引用http://www.2cto.com/os/201111/111269.html的方法.亲测可用 该进程是Http.sys.它是http API的驱动组件,Http栈服务器.如果该端口被Http ...
- SQLServer游标详解
一.游标概念 我们知道,关系数据库所有的关系运算其实是集合与集合的运算,它的输入是集合输出同样是集合,有时需要对结果集逐行进行处理,这时就需要用到游标.我们对游标的使用一本遵循“五步法”:声明游标—& ...
- Oracle 中的Userenv()
1.USEREVN() 返回当前用户环境的信息,opt可以是:ENTRYID,SESSIONID,TERMINAL,ISDBA,LABLE,LANGUAGE,CLIENT_INFO,LANG,VSIZ ...
- Android 轮询之 Service + AlarmManager+Thread (转)
android中涉及到将服务器中数据变化信息通知用户一般有两种办法,推送和轮询. 消息推送是服务端主动发消息给客户端,因为第一时间知道数据发生变化的是服务器自己,所以推送的优势是实时性高.但服务器主动 ...
- linux学习笔记之零散笔记。
部分知识,不足以成为完整博文.但又不能随意抛弃. 1,文件名建议字符集:字母+数字+ ./-/_ 尽量不要使用其他符号.因为特殊符号在很多功能中已经被占用. 2,系统调用通常提供最小接口(最简易) ...
- mysql中select into 和sql中的select into 对比
现在有张表为student,我想将这个表里面的数据复制到一个为dust的新表中去.answer 01: create table dust select * from student;//用于复制前未 ...
- oracle学习-安装卸载
- flash的as操作XML
//as3.0 var myXML:XML = new XML(); var XML_URL:String = "nav.config"; var myXMLURL:URLRequ ...
- HTML5的结构学习(2) --- 新增的非主体结构元素
除了上一篇学习到的主体结构元素之外,html5还增加了一些表示逻辑结构和附加信息的非主体结构元素: 1.header 解释:一种具有引导和导航作用的结构元素. 用途:通常用来放置整个页面或者页面内某一 ...
- c#接口定义与应用
public interface IBankAccount //只能加public修饰符,或者什么都不加 { void Playin(decimal money); //函数前不加任何修饰符号 boo ...