VarSetCapacity()

AutoHotkey

VarSetCapacity()

增加或清空变量占用的内存。通常只有在特殊情况下才需要,例如 DllCall

GrantedCapacity := VarSetCapacity(UnquotedVarName [, RequestedCapacity, FillByte])

参数

GrantedCapacity

变量现在占用的字节数, 它会大于或等于 RequestedCapacity. 如果 VarName 不是有效的变量名 (例如原义的字符串或数字), 则返回 0. 如果系统没有足够的内存来进行变更 (很罕见), 则会显示错误对话框并返回当前的容量, 此行为可能在将来的版本中改变.

UnquotedVarName

变量名 (没有括在百分号中). 例如: VarSetCapacity(MyVar, 1000). 这也可以是动态变量, 例如 Array%i%函数的 ByRef 参数.

RequestedCapacity

如果省略, 则返回变量当前的容量且不会改变它的内容. 否则, 会丢失变量中的所有内容 (变量变成空的).

RequestedCapacity 中指定字节数, 表示在调整后变量要占用的空间. 对于 Unicode 字符串, 这里应是长度的两倍. RequestedCapacity 不包含内部的零终止符. 例如, 指定 1 会允许变量最多占用一字节的空间加上内部的终止符. 注: 如果后面脚本给变量分配更大的值, 那么它会自动扩展容量.

因此可以经常简单地调用此函数来确保变量占用最小的空间, 考虑到性能原因, 只有在 RequestedCapacity 为 0 时它才会缩小变量的容量. 换句话说, 如果变量的容量已经大于 RequestedCapacity, 则不会减小它的容量 (但为了保持一致, 变量会被置空).

因此, 要明确地缩小变量, 首先请使用 VarSetCapacity(Var, 0) 释放它占用的内存, 然后使用 VarSetCapacity(Var, NewCapacity) 或者简单地让它自动按需从零扩展.

考虑到性能的原因, 要释放一个原来容量小于 64 字节 (在 Unicode 版本中为 128 字节) 的变量可能会没有效果, 因为它的内存是永久性的. 此时, 会返回当前容量而不是 0.

考虑到性能的原因, 容量小于 4096 字节的变量的内存不能通过赋值空字符串的方法来释放 (例如 Var := ""). 然而, VarSetCapacity(Var, 0) 会释放.

在 v1.0.44.03+, 在 RequestedCapacity 指定 -1 来更新变量内部存储的字符串长度为当前内容的长度. 这可用在间接修改变量的时候, 例如通过 DllCall() 传递它的 地址. 在这种模式中, VarSetCapacity() 返回以字节为单位的长度而不是容量.

FillByte

此参数通常省略, 此时不会对目标变量的内存进行初始化 (作为替代, 只是像上面描述的那样简单地把变量置空). 否则, 请指定介于 0 和 255 之间的整数. 目标变量内存区域的每个字节 (它的当前容量, 可能大于 RequestedCapacity) 会被设为这个数字. 零显然是最常用的值, 这可用于要在变量中保存原始的二进制数据时, 例如 DllCall 结构.

备注

除了在 DllCall 中描述的它的用法, 此函数还可以用来在通过逐步连接的方法构造字符串时提升性能. 这是因为当您可以确定字符串的最终长度时可以避免多次自动的容量大小调整. 在这种情况中, RequestedCapacity 不需要太准确: 如果容量太小, 性能仍然会提升, 而当分配的容量用完时变量会开始自动扩展. 如果容量太大, 会浪费一些内存, 不过只是暂时的, 因为在操作完成后使用 VarSetCapacity(Var, 0)Var := "" 后可以释放所有的内存.

#MaxMem 只限制变量自动扩展所占用的容量. 它不会影响 VarSetCapacity.

相关

DllCall, #MaxMem, NumPut, NumGet

示例

; 通过让 MyVar 有足够的空间进行操作来优化性能.
VarSetCapacity(MyVar, 10240000)  ; ~10 MB
Loop
{
    ...
    MyVar = %MyVar%%StringToConcatenate%
    ...
}
; 计算字符串需要的缓冲空间.
bytes_per_char := A_IsUnicode ? 2 : 1
max_chars := 500
max_bytes := max_chars * bytes_per_char

Loop 2
{
    ; 分配用于 DllCall 的空间.
    VarSetCapacity(buf, max_bytes)

    if A_Index = 1
        ; 通过 DllCall 间接修改变量.
        DllCall("wsprintf", "ptr", &buf, "str", "0x%08x", "uint", 4919)
    else
        ; 使用 "str" 来自动更新长度:
        DllCall("wsprintf", "str", buf, "str", "0x%08x", "uint", 4919)

    ; 连接字符串以演示为什么需要更新长度:
    wrong_str := buf . "<end>"
    wrong_len := StrLen(buf)

    ; 更新变量的长度.
    VarSetCapacity(buf, -1)

    right_str := buf . "<end>"
    right_len := StrLen(buf)

    MsgBox,
    (
    Before updating
      String: %wrong_str%
      Length: %wrong_len%

    After updating
      String: %right_str%
      Length: %right_len%
    )
}