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运行时在启动时保留(或操作系统提供)大量内存。