O consumo de memória do GetRef (coleta de lixo) foi alterado com KB4525236

11

Ocorremos problemas de falta de memória após a instalação do KB4525236 em nossos servidores Windows 2016 / Windows 10 Clients. Essa correção de segurança parece ter mudado o momento em que a memória é coletada como lixo ao chamar uma função GetRef.

Pré KB4525236

Cada instância criada em uma função chamada através de GetRefcoleta de lixo foi coletada assim que a variável de instância foi definida comonothing

Mensagem KB4525236

Cada instância criada em uma função chamada através GetRefpermanece na memória e é coletada como lixo somente quando a função inteira é concluída . Ao criar instâncias em um loop, isso pode aumentar rapidamente e levar a uma falta de memória, especialmente em um processo de 32 bits.

Questões

  • não conseguimos encontrar nada relevante on-line, portanto, gostaríamos de receber confirmação de outras pessoas com o mesmo problema.
    EDIT arranha isso: esse é o mesmo problema, mas ainda não há solução
    (bug vbscript.dll class_terminate desde KB4524570 (12 de novembro de 2019) Windows 10 1903)
  • se alguém puder verificar e conhecer uma solução viável, isso seria incrível.

POC

O script a seguir em execução em um dispositivo com o KB4525236 instalado mostra a diferença na coleta de lixo quando

  • chamado diretamente: a segunda instância é criada somente após a destruição da primeira instância (esse é o nosso comportamento desejado)
  • chamado através GetRef: a segunda instância é criada antes que a primeira instância seja destruída, então temos duas instâncias usando memória.

salve como: KB4525236.vbs
execute como: 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
Lieven Keersmaekers
fonte
11
@Ankymart - o problema é que as instâncias criadas em GetRef()não recebem lixo coletado até o GetRef()final. Isso é diferente do que era. Temos funções chamadas através da GetRef()criação de milhares de instâncias e elas continuam acumulando memória até o GetRef()fim, enquanto no passado foram liberadas durante a execução do loop GetRef().
Lieven Keersmaekers
11
Obrigado por esclarecer, não tenho certeza do que você poderá fazer sobre esse tbh. Imagine se alguém souber, será @ eric-lippert enquanto eles trabalham na equipe original que criou o VBScript.
Lankymart
2
Eu tenho o comportamento que você descreve no Windows 7 sem o KB4525236 ou o KB4524570 (aparentemente, há outro KB que faz isso no Windows 7). Ainda assim, não há coleta de lixo no VBScript, os objetos devem ser destruídos quando a contagem de referência cai para zero. Se isso não acontecer, é um bug do mecanismo, e não uma maneira diferente de funcionamento do GC.
GSerg 8/02
2
Este é o caso mesmo sem variáveis ​​explícitas. Dois With New IDummyInstance : End Withblocos ainda produzem "Inicializar Primeira Instância, Inicializar Segunda Instância, Terminar Primeira Instância, Terminar Segunda Instância". Isso está muito errado, deve ser relatado. Além da coisa consumo de memória, quebra completamente este .
GSerg 8/02
11
@GSerg - Você tem um canal para denunciar isso? Nada me chega mais rápido do que tentar descobrir onde denunciar problemas. Esta página de suporte, por exemplo, leva a essa página de suporte, que efetivamente leva a nada.
Lieven Keersmaekers

Respostas:

1

Como não tenho uma solução ou uma fonte oficial que explique o problema, estava esperando a recompensa expirar.

Eu vim com uma solução desagradável que pode ajudar até que o bug seja corrigido.

A solução alternativa é não usar nenhuma variável local para manter instâncias de objeto em procedimentos que possam ser executados GetRef.

Em vez de variáveis ​​implícitas ou explícitas, o uso de um objeto de dicionário local (ou global, se não houver recursão) para conter instâncias de objetos e chamá-las através desse dicionário funciona.

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

Parece valer a pena usar se você tiver um script que não seja muito complicado.

Kul-Tigin
fonte
11
Apenas testei e posso confirmar que funciona na minha máquina. Vou marcar isso como a solução. É o melhor até a Microsoft fornecer uma correção (supondo que eles reconheçam que isso é um bug) .
Lieven Keersmaekers