VBA RtlMoveMemory仅适用于ByVal
工作守则如下:VBA RtlMoveMemory仅适用于ByVal,vba,memory,Vba,Memory,工作守则如下: Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSource As Any, ByVal ByteLen As Long) Sub Test() Dim Long1 As Long Dim Long2 As Long Long1 = 1000 CopyMemory ByVal VarPtr(Long2), ByVal VarPtr(Long
Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSource As Any, ByVal ByteLen As Long)
Sub Test()
Dim Long1 As Long
Dim Long2 As Long
Long1 = 1000
CopyMemory ByVal VarPtr(Long2), ByVal VarPtr(Long1), 4
Debug.Print VarPtr(Long1)
Debug.Print Long2
End Sub
我有两个问题:
我的理解是,VB运行时在Long1和Long2超出范围时释放了它们的内存。为什么Debug.Print VarPtr(Long1)
在每次运行程序时都返回相同的地址?VB运行时是否为变量保留了一定的内存?我相信是这样的,因为即使我做了一些事情(例如关闭Chrome标签)来释放堆中的内存,它保持显示相同的地址
为什么我需要使用
ByVal
来获得正确的结果?我知道CopyMemory
只是将整数VarPtr(Long1)
指向的地址中的若干字节移动到整数VarPtr(Long2)
指向的地址,但我不知道为什么我必须使用关键字ByVal
,否则它只返回0
。我认为VBA可能会将ByRef
作为默认值,而ByRef
意味着将字节从存储Long1
地址的地址(基本上是对VarPtr返回值的引用,它只是一个整数)复制到存储Long2
地址的地址,这也没什么。但是,如果我故意使用ByRef
基元局部变量存储在上,VBA只会给我错误消息,因此地址取决于调用例程的顺序,您可以通过一个简单的示例看到这一点:
Sub showAdresses()
myTest
callTest
callTest
myTest
End Sub
Sub callTest()
myTest
End Sub
Sub myTest()
Dim x As Long
Debug.Print VarPtr(x)
End Sub
您将看到第一个和最后一个调用的地址相同,而中间调用的地址也相同——这仅仅是因为堆栈上有用于中间例程的空间。当一个子例程完成时,堆栈上消耗的空间被释放,并且(这是堆栈的性质)立即被重用,因此,如果再次调用同一例程,同一变量将获得相同的地址(但VBA将其初始化)
对于调用
CopyMemory
时的ByVal
关键字:我假设对VarPtr
的调用返回一个指针,您将指针作为值传递,否则您将传递指针的地址。关闭Chrome选项卡不会影响Excel内存管理。通过进程隔离,操作系统在让每个进程都认为自己有自己的地址空间方面做得很好。我意识到,在操作系统级别,Windows确实会对块进行翻页和翻页,但Excel不会这样看。exe@SMeaden谢谢我不知道操作系统是如何工作的,谢谢你的启示。我天真的解释是,VB运行时在启动时保留(或操作系统提供)大量内存。