GetRef 的内存消耗(垃圾收集)随 KB4525236 发生变化
GetRef's memory consumption (garbage collection) changed with KB4525236
我们在 Windows 2016 Servers/Windows 10 个客户端上安装 KB4525236 后遇到内存不足问题。此安全修复程序似乎更改了通过 GetRef
.
调用函数时内存被垃圾回收的时刻
Pré KB4525236
在通过 GetRef
调用的函数中创建的每个实例在实例变量设置为 nothing
后立即被垃圾收集
Post KB4525236
在通过 GetRef
调用的函数中创建的每个实例都保留在内存中,并且 只有在整个函数完成时才收集垃圾。在循环中创建实例时,这会迅速累积并导致内存不足,尤其是在 32 位进程中。
问题
- 我们无法在网上找到任何相关信息,因此我们希望得到遇到同样问题的其他人的确认。
编辑 从头开始:this 是同一个问题,但目前还没有解决方案
(vbscript.dll class_terminate 自 KB4524570(2019 年 11 月 12 日)以来的错误 Windows 10 1903)
- 如果有人可以验证并知道可行的解决方案,那就太棒了。
POC
安装了 KB4525236 的设备上的以下脚本 运行ning 显示了
时垃圾收集的差异
- 直接调用:仅在第一个实例被销毁后创建第二个实例(这是我们想要的行为)
- 通过
GetRef
调用:第二个实例在 在 第一个实例被销毁之前创建,因此当有两个实例使用内存时。
另存为:KB4525236.vbs
运行 为:wscript KB4525236.vbs
Dim Name, Log
Class IDummyInstance
Dim FName
Sub Class_Initialize
FName = Name
Log = Log & "Initialize " & FName & VbNewLine
End Sub
Sub Class_Terminate
Log = Log & "Terminate " & FName & vbNewLine
End Sub
End Class
Sub CreateDestroyTwoInstances
Dim DummyInstance
Name = "First Instance"
Set DummyInstance = New IDummyInstance
Set DummyInstance = Nothing
Name = "Second Instance"
Set DummyInstance = New IDummyInstance
Set DummyInstance = Nothing
End Sub
Log = "(1) Direct Call :" & VbNewLine
Call CreateDestroyTwoInstances
Log = VbNewLine & Log & "(2) GetRef Call :" & vbNewLine
Set GetRefCall = GetRef ("CreateDestroyTwoInstances")
Call GetRefCall
MsgBox Log
由于我没有解决方案或官方来源来解释这个问题,所以我一直在等待赏金到期。
我想出了一个令人不愉快的解决方法,可以在错误修复之前提供帮助。
解决方法是不使用任何局部变量来保存可能通过 GetRef
执行的过程中的对象实例。
不使用隐式或显式变量,而是使用局部(如果没有递归则为全局)字典对象来保存对象实例并通过该字典调用它们。
Sub CreateDestroyTwoInstances
Dim Refs
Set Refs = CreateObject("Scripting.Dictionary")
Name = "First Instance"
Refs.Add "DummyInstance", New IDummyInstance
' Call Refs("DummyInstance").DoSomething()
Refs.Remove "DummyInstance"
Name = "Second Instance"
Refs.Add "DummyInstance", New IDummyInstance
' Call Refs("DummyInstance").DoSomething()
Refs.Remove "DummyInstance"
End Sub
如果你有一个不太复杂的脚本,似乎值得使用。
有一种迂回的方法可以让 VBScript 终止对象 'now' 而不是稍后。
通过将以下观察结果拼凑起来:
如果调用 class 实例的成员函数,对象“清理”将延迟到函数的末尾。
如果通过引用传递参数,您可以修改值(例如设置为 Nothing)。
你可能会得到这样的结果:
Class Disposal
Public Sub Dispose(ByRef oRef)
Set oRef = Nothing
End Sub
End Class
' A global instance ready for use.
Dim GD: Set GD = New Disposal
要使用处置,您需要替换:
Set x = Nothing
与:
GD.Dispose x
下面是对将对象传递给 'dispose of' 时发生的情况的粗略解释:
- Dispose 引用一个对象并将其设置为 Nothing(不言自明)。
- 在函数结束时,VBScript 'sees' 不再有对该对象的引用。
- VBScript 终止对象。
或者至少,这就是我认为它正在做的...
以下是应用于 POC 的解决方案:
Class Disposal
Public Sub Dispose(ByRef oRef)
Set oRef = Nothing
End Sub
End Class
' A global instance ready for use.
Dim GD: Set GD = New Disposal
Dim Name, Log
Class IDummyInstance
Dim FName
Sub Class_Initialize
FName = Name
Log = Log & "Initialize " & FName & VbNewLine
End Sub
Sub Class_Terminate
Log = Log & "Terminate " & FName & vbNewLine
End Sub
End Class
Sub CreateDestroyTwoInstances
Dim DummyInstance
Name = "First Instance"
Set DummyInstance = New IDummyInstance
GD.Dispose DummyInstance 'Set DummyInstance = Nothing
Name = "Second Instance"
Set DummyInstance = New IDummyInstance
GD.Dispose DummyInstance 'Set DummyInstance = Nothing
End Sub
Log = "(1) Direct Call :" & VbNewLine
Call CreateDestroyTwoInstances
Log = VbNewLine & Log & "(2) GetRef Call :" & vbNewLine
Set GetRefCall = GetRef ("CreateDestroyTwoInstances")
Call GetRefCall
MsgBox Log
希望这能帮助那些在 2021 年及以后仍然坚持使用 VBScript 的人...
好问题。我是通过 Microsoft 论坛找到它的 post
这个 SO 的提问者在 Microsoft 线程上面添加了一个 link。
KB5005101 的发行说明中引用了该 Microsoft 线程(对于 Windows 10 21H1 - 其他 Windows 10 版本将有类似的 KB)。
Link 至 Microsoft 发行说明:https://support.microsoft.com/en-us/topic/september-1-2021-kb5005101-os-builds-19041-1202-19042-1202-and-19043-1202-preview-82a50f27-a56f-4212-96ce-1554e8058dc1
微软声称已经修复了这个问题
Addresses a memory leak that occurs when you use nested classes within VBScript.
在发行说明中,末尾的 VBScript
单词是对该 Microsoft 论坛主题的 hyperlink。比较微妙...
无论如何,虽然我不是 VBScript 的常客,但作为 COM 的长期用户,并且无论如何对 reader 这类问题感兴趣,我想我会分享最终应该是什么一旦每个人都获得了他们的每月补丁,就有了明确的答案。这些发行说明只能追溯到 Windows 10 2004,因此 1909 和更早的版本可能不走运,Windows 7 位用户可能会受此影响。
我们在 Windows 2016 Servers/Windows 10 个客户端上安装 KB4525236 后遇到内存不足问题。此安全修复程序似乎更改了通过 GetRef
.
Pré KB4525236
在通过 GetRef
调用的函数中创建的每个实例在实例变量设置为 nothing
Post KB4525236
在通过 GetRef
调用的函数中创建的每个实例都保留在内存中,并且 只有在整个函数完成时才收集垃圾。在循环中创建实例时,这会迅速累积并导致内存不足,尤其是在 32 位进程中。
问题
- 我们无法在网上找到任何相关信息,因此我们希望得到遇到同样问题的其他人的确认。
编辑 从头开始:this 是同一个问题,但目前还没有解决方案
(vbscript.dll class_terminate 自 KB4524570(2019 年 11 月 12 日)以来的错误 Windows 10 1903) - 如果有人可以验证并知道可行的解决方案,那就太棒了。
POC
安装了 KB4525236 的设备上的以下脚本 运行ning 显示了
时垃圾收集的差异- 直接调用:仅在第一个实例被销毁后创建第二个实例(这是我们想要的行为)
- 通过
GetRef
调用:第二个实例在 在 第一个实例被销毁之前创建,因此当有两个实例使用内存时。
另存为:KB4525236.vbs
运行 为:wscript KB4525236.vbs
Dim Name, Log
Class IDummyInstance
Dim FName
Sub Class_Initialize
FName = Name
Log = Log & "Initialize " & FName & VbNewLine
End Sub
Sub Class_Terminate
Log = Log & "Terminate " & FName & vbNewLine
End Sub
End Class
Sub CreateDestroyTwoInstances
Dim DummyInstance
Name = "First Instance"
Set DummyInstance = New IDummyInstance
Set DummyInstance = Nothing
Name = "Second Instance"
Set DummyInstance = New IDummyInstance
Set DummyInstance = Nothing
End Sub
Log = "(1) Direct Call :" & VbNewLine
Call CreateDestroyTwoInstances
Log = VbNewLine & Log & "(2) GetRef Call :" & vbNewLine
Set GetRefCall = GetRef ("CreateDestroyTwoInstances")
Call GetRefCall
MsgBox Log
由于我没有解决方案或官方来源来解释这个问题,所以我一直在等待赏金到期。
我想出了一个令人不愉快的解决方法,可以在错误修复之前提供帮助。
解决方法是不使用任何局部变量来保存可能通过 GetRef
执行的过程中的对象实例。
不使用隐式或显式变量,而是使用局部(如果没有递归则为全局)字典对象来保存对象实例并通过该字典调用它们。
Sub CreateDestroyTwoInstances
Dim Refs
Set Refs = CreateObject("Scripting.Dictionary")
Name = "First Instance"
Refs.Add "DummyInstance", New IDummyInstance
' Call Refs("DummyInstance").DoSomething()
Refs.Remove "DummyInstance"
Name = "Second Instance"
Refs.Add "DummyInstance", New IDummyInstance
' Call Refs("DummyInstance").DoSomething()
Refs.Remove "DummyInstance"
End Sub
如果你有一个不太复杂的脚本,似乎值得使用。
有一种迂回的方法可以让 VBScript 终止对象 'now' 而不是稍后。
通过将以下观察结果拼凑起来:
如果调用 class 实例的成员函数,对象“清理”将延迟到函数的末尾。
如果通过引用传递参数,您可以修改值(例如设置为 Nothing)。
你可能会得到这样的结果:
Class Disposal
Public Sub Dispose(ByRef oRef)
Set oRef = Nothing
End Sub
End Class
' A global instance ready for use.
Dim GD: Set GD = New Disposal
要使用处置,您需要替换:
Set x = Nothing
与:
GD.Dispose x
下面是对将对象传递给 'dispose of' 时发生的情况的粗略解释:
- Dispose 引用一个对象并将其设置为 Nothing(不言自明)。
- 在函数结束时,VBScript 'sees' 不再有对该对象的引用。
- VBScript 终止对象。
或者至少,这就是我认为它正在做的...
以下是应用于 POC 的解决方案:
Class Disposal
Public Sub Dispose(ByRef oRef)
Set oRef = Nothing
End Sub
End Class
' A global instance ready for use.
Dim GD: Set GD = New Disposal
Dim Name, Log
Class IDummyInstance
Dim FName
Sub Class_Initialize
FName = Name
Log = Log & "Initialize " & FName & VbNewLine
End Sub
Sub Class_Terminate
Log = Log & "Terminate " & FName & vbNewLine
End Sub
End Class
Sub CreateDestroyTwoInstances
Dim DummyInstance
Name = "First Instance"
Set DummyInstance = New IDummyInstance
GD.Dispose DummyInstance 'Set DummyInstance = Nothing
Name = "Second Instance"
Set DummyInstance = New IDummyInstance
GD.Dispose DummyInstance 'Set DummyInstance = Nothing
End Sub
Log = "(1) Direct Call :" & VbNewLine
Call CreateDestroyTwoInstances
Log = VbNewLine & Log & "(2) GetRef Call :" & vbNewLine
Set GetRefCall = GetRef ("CreateDestroyTwoInstances")
Call GetRefCall
MsgBox Log
希望这能帮助那些在 2021 年及以后仍然坚持使用 VBScript 的人...
好问题。我是通过 Microsoft 论坛找到它的 post
这个 SO 的提问者在 Microsoft 线程上面添加了一个 link。
KB5005101 的发行说明中引用了该 Microsoft 线程(对于 Windows 10 21H1 - 其他 Windows 10 版本将有类似的 KB)。 Link 至 Microsoft 发行说明:https://support.microsoft.com/en-us/topic/september-1-2021-kb5005101-os-builds-19041-1202-19042-1202-and-19043-1202-preview-82a50f27-a56f-4212-96ce-1554e8058dc1
微软声称已经修复了这个问题
Addresses a memory leak that occurs when you use nested classes within VBScript.
在发行说明中,末尾的 VBScript
单词是对该 Microsoft 论坛主题的 hyperlink。比较微妙...
无论如何,虽然我不是 VBScript 的常客,但作为 COM 的长期用户,并且无论如何对 reader 这类问题感兴趣,我想我会分享最终应该是什么一旦每个人都获得了他们的每月补丁,就有了明确的答案。这些发行说明只能追溯到 Windows 10 2004,因此 1909 和更早的版本可能不走运,Windows 7 位用户可能会受此影响。