KB4525236更改了GetRef的内存消耗(垃圾回收)


11

在Windows 2016 Server / Windows 10客户端上安装KB4525236后,我们会遇到内存不足的问题。通过调用函数时,内存被垃圾回收时,此安全修复程序似乎已发生更改GetRef

PréKB4525236

GetRef在实例变量设置为时,在通过调用的函数中创建的每个实例都会被垃圾回收。nothing

帖子KB4525236

在通过调用的函数中创建的每个实例都GetRef保留在内存中,并且仅在整个函数完成时才进行垃圾回收。在循环中创建实例时,这可能会迅速累加并导致内存不足,尤其是在32位进程中。

问题

  • 我们在网上找不到任何相关内容,因此我们希望获得其他遇到相同问题的人的确认。
    编辑从零开始:是相同的问题,但尚未解决
    (自KB4524570(2019年11月12日)Windows 10 1903起vbscript.dll class_terminate bug
  • 如果有人可以验证并知道可行的解决方案,那就太好了。

POC

在安装了KB4525236的设备上运行的以下脚本显示了以下情况下垃圾收集的区别:

  • 直接调用:仅第一个实例销毁后才创建第二个实例(这是我们期望的行为)
  • 通过调用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

1
@Lankymart-问题是在中创建的实例GetRef()直到GetRef()结束都不会被垃圾收集。那是什么不同。我们具有通过GetRef()创建1000个实例来调用的函数,并且它们一直在累积内存,直到GetRef()结束为止,而在过去,它们在执行中的循环时被释放了GetRef()
Lieven Keersmaekers

1
感谢您的澄清,我不确定您将如何处理该tbh。想象一下,如果有人知道,那将是@ eric-lippert,因为他们在建立VBScript的原始团队中工作。
Lankymart

2
我有您描述的在Windows 7上没有KB4525236或KB4524570的行为(显然还有另一个KB可以对Windows 7做到这一点)。但是,VBScript中没有垃圾回收,当对象的引用计数降至零时,必须销毁这些对象。如果那没有发生,那是引擎错误,而不是GC功能的另一种方式。
GSerg

2
即使没有显式变量也是如此。两个With New IDummyInstance : End With块仍然产生“初始化第一实例,初始化第二实例,终止第一实例,终止第二实例”。这是非常错误的,应该报告。除了内存消耗之外,它还完全打破了这一点
GSerg

1
@GSerg-您碰巧有一个举报此消息的渠道吗?没有比设法弄清楚报告问题的地方快的多了。这种支持页面 例如导致这种支持页面有效地导致了什么。
Lieven Keersmaekers

Answers:


1

由于我没有解决方案或没有官方消息解释该问题,因此我在等赏金到期。

我提出了一个不愉快的解决方法,该问题可以在错误修复之前提供帮助。

解决方法是不要使用任何局部变量将对象实例保存在可能通过来执行的过程中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

如果您的脚本不太复杂,那么似乎值得使用。


1
刚刚测试过,我可以确认它可以在我的机器上正常工作。我将其标记为解决方案。在Microsoft提供修复程序之前,这是最好的方法(假设他们承认这是一个错误)
Lieven Keersmaekers
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.