Потребление памяти GetRef (сборка мусора) изменено с помощью KB4525236.

У нас возникают проблемы с нехваткой памяти после установки KB4525236 на наших серверах Windows 2016/клиентах Windows 10. Это исправление безопасности, похоже, изменило момент, когда память очищается сборщиком мусора при вызове функции через GetRef.

Pré KB4525236

Каждый экземпляр, созданный в функции, вызываемой через GetRef, собирал мусор, как только переменная экземпляра была установлена ​​на nothing.

Сообщение KB4525236

Каждый экземпляр, созданный в функции, вызываемой через GetRef, остается в памяти и собирается мусором только после завершения всей функции. При создании экземпляров в цикле это может быстро накапливаться и приводить к нехватке памяти, особенно в 32-разрядном процессе.

Вопросы

  • мы не можем найти ничего подходящего в Интернете, поэтому мы хотели бы получить подтверждение от других, столкнувшихся с той же проблемой.
    ИЗМЕНИТЬ зачеркните это: это та же проблема, но без решения, как из еще
    (ошибка vbscript.dll class_terminate начиная с KB4524570 (12 ноября 2019 г.) Windows 10 1903)
  • если кто-нибудь может проверить и знает работоспособное решение, это было бы здорово.

ПОС

следующий скрипт, работающий на устройстве с установленным 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

person Lieven Keersmaekers    schedule 06.02.2020    source источник
comment
Если вы беспокоитесь о потреблении памяти GetRef(), почему бы просто не установить ссылку на объект GetRefCall на Nothing, чтобы вручную очистить память, вместо того, чтобы полагаться на сборку мусора VBScript?   -  person user692942    schedule 06.02.2020
comment
@Lankymart - проблема в том, что экземпляры, созданные в GetRef(), не собирают мусор, пока не закончится GetRef(). Это отличается от того, что было. У нас есть функции, вызываемые через GetRef(), создающие 1000 экземпляров, и они продолжают накапливать память до тех пор, пока не закончится GetRef(), тогда как в прошлом они освобождались при выполнении цикла в GetRef().   -  person Lieven Keersmaekers    schedule 06.02.2020
comment
Спасибо за разъяснение, я не уверен, что вы сможете с этим поделать. Представьте, если кто-нибудь знает, это будет @eric-lippert, поскольку они работали над оригинальной командой, которая создала VBScript.   -  person user692942    schedule 06.02.2020
comment
@LankyMart - Эрик Липперт работал над сборщиком мусора, но, согласно сообщению здесь, на SO, это было более 10 лет назад. Я бы хотел узнать его мнение об этом, скрестив пальцы;)   -  person Lieven Keersmaekers    schedule 06.02.2020
comment
У меня поведение, которое вы описываете, в Windows 7 без KB4525236 или KB4524570 (очевидно, есть еще один KB, который делает это для Windows 7). Тем не менее, в VBScript нет сборки мусора, объекты должны уничтожаться, когда их счетчик ссылок падает до нуля. Если этого не происходит, то это ошибка движка, а не другой способ функционирования сборщика мусора.   -  person GSerg    schedule 08.02.2020
comment
Это так даже без явных переменных. Два блока With New IDummyInstance : End With по-прежнему производят инициализацию первого экземпляра, инициализацию второго экземпляра, завершение первого экземпляра, завершение второго экземпляра. Это очень неправильно, об этом следует сообщить. Помимо потребления памяти, это полностью нарушает это.   -  person GSerg    schedule 08.02.2020
comment
@GSerg - Что касается наших тестов, память действительно освобождается, но момент, когда изменяется, так что можно спорить, что это ошибка движка. Если это не изменить, это действительно вынуждает нас переписывать наш код и проявлять особую осторожность, чтобы не создавать много объектов в жестком цикле через вызов GetRef. Я не знаю, с чего начать, чтобы сообщить об этом в Microsoft, кроме видимости, которую он получает здесь, на SO и здесь.   -  person Lieven Keersmaekers    schedule 08.02.2020
comment
@LievenKeersmaekers Это ошибка движка, потому что when является частью контракта с подсчетом ссылок COM. Это не ошибка утечки памяти, но это ошибка. Насколько я понимаю, вы даже не можете проявлять особую осторожность, потому что единственное, что это исправляет, - это избегать GetRef. Хотя я бы проверил, что происходит, когда вы вызываете вспомогательную подпрограмму из CreateDestroyTwoInstances, которая создает, использует и уничтожает IDummyInstance, не возвращая ее в CreateDestroyTwoInstances. Что я и сделал, и нет, такое же поведение.   -  person GSerg    schedule 08.02.2020
comment
@GSerg - У вас случайно нет канала, чтобы сообщить об этом? Ничто не доходит до меня быстрее, чем попытка выяснить, куда сообщать о проблемах. Эта страница поддержки, например, ведет к эта страница поддержки, которая фактически ни к чему не приводит.   -  person Lieven Keersmaekers    schedule 08.02.2020
comment
@LievenKeersmaekers Нет, не знаю, и это будет выглядеть никто не делает. Я думаю, попробуйте приложение центра обратной связи.   -  person GSerg    schedule 08.02.2020
comment
@Gserg - спасибо. По крайней мере, это сделал мой день ;)   -  person Lieven Keersmaekers    schedule 08.02.2020
comment
@GSerg - также из этого блога видно, что путь лежит через answer.microsoft.com. Очевидно, это также рекомендуется для связи с разработчиками. Я уже ссылался на answer.microsoft.com в своем вопросе. После прочтения блога и в интересах сохранения здравомыслия я остановлюсь на этом.   -  person Lieven Keersmaekers    schedule 08.02.2020


Ответы (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

Кажется, его стоит использовать, если у вас есть не слишком сложный скрипт.

person Kul-Tigin    schedule 18.02.2020
comment
Только что протестировал его, и я могу подтвердить, что он работает на моей машине. Я собираюсь отметить это как решение. Пока Microsoft не предоставит исправление (при условии, что они признают, что это ошибка). - person Lieven Keersmaekers; 18.02.2020