Zużycie pamięci GetRef (odśmiecanie) zmieniło się z KB4525236

11

Problemy z brakiem pamięci występują po zainstalowaniu KB4525236 na naszych serwerach / klientach z systemem Windows 10. Wydaje się, że ta poprawka zabezpieczeń zmieniła się w momencie, gdy pamięć jest zbierana podczas wywoływania funkcji GetRef.

Pre KB4525236

Każde wystąpienie utworzone w funkcji wywoływanej przez GetRefzostało pobrane śmieci, gdy tylko zmienna wystąpienia została ustawiona nanothing

Opublikuj KB4525236

Każde wystąpienie utworzone w funkcji wywoływanej przez GetRefpozostaje w pamięci i jest usuwane w pamięci tylko po zakończeniu całej funkcji . Podczas tworzenia instancji w pętli może to szybko zsumować się i doprowadzić do braku pamięci, szczególnie w procesie 32-bitowym.

pytania

  • nie możemy znaleźć niczego istotnego w Internecie, dlatego chcielibyśmy uzyskać potwierdzenie od innych osób mających ten sam problem.
    EDYCJA podstaw: to ten sam problem, ale na razie brak rozwiązania
    (błąd vbscript.dll class_terminate od KB4524570 (12 listopada 2019 r.) Windows 10 1903)
  • jeśli ktokolwiek może zweryfikować i zna realne rozwiązanie, byłoby świetnie.

POC

poniższy skrypt działający na urządzeniu z zainstalowaną wersją KB4525236 pokazuje różnicę w zbieraniu pamięci, kiedy

  • wywoływane bezpośrednio: druga instancja jest tworzona dopiero po zniszczeniu pierwszej instancji (jest to nasze pożądane zachowanie)
  • wywoływane przez GetRef: druga instancja jest tworzona przed zniszczeniem pierwszej instancji, więc dwie instancje używają pamięci.

zapisz jako: KB4525236.vbs
uruchom jako: 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
źródło
1
@Lankymart - problem polega na tym, że utworzone instancje GetRef()nie pobierają śmieci do GetRef()końca. To różni się od tego, co to było. Mamy funkcje wywoływane przez GetRef()tworzenie 1000 wystąpień, które gromadzą pamięć aż do GetRef()końca, podczas gdy w przeszłości były uwalniane podczas wykonywania pętli GetRef().
Lieven Keersmaekers,
1
Dzięki za wyjaśnienie, nie jestem pewien, co będziesz w stanie zrobić z tym tbh. Wyobraź sobie, że jeśli ktoś wie, będzie to @ eric-lippert, pracując nad oryginalnym zespołem, który zbudował VBScript.
Lankymart
2
Mam zachowanie, które opisujesz w systemie Windows 7 bez KB4525236 lub KB4524570 (najwyraźniej istnieje inny KB, który robi to z Windows 7). Mimo to w VBScript nie ma wyrzucania elementów bezużytecznych, obiekty muszą zostać zniszczone, gdy ich liczba odniesień spadnie do zera. Jeśli tak się nie stanie, jest to błąd silnika, a nie inny sposób działania GC.
GSerg
2
Dzieje się tak nawet bez wyraźnych zmiennych. Dwa With New IDummyInstance : End Withbloki nadal generują „Zainicjuj pierwszą instancję, Zainicjuj drugą instancję, Zakończ pierwszą instancję, Zakończ drugą instancję”. To bardzo źle, należy to zgłosić. Oprócz rzeczy, zużycie pamięci, to całkowicie łamie to .
GSerg
1
@GSerg - Czy zdarza się, że masz kanał, aby to zgłosić? Nic nie dociera do mnie szybciej niż próba znalezienia miejsca zgłoszenia problemów. Ta strona wsparcia na przykład prowadzi do strony wsparcia, która faktycznie prowadzi do niczego.
Lieven Keersmaekers

Odpowiedzi:

1

Ponieważ nie mam rozwiązania ani oficjalnego źródła wyjaśniającego problem, czekałem na wygraną.

Wymyśliłem nieprzyjemne obejście, które może pomóc, dopóki błąd nie zostanie naprawiony.

Obejściem tego problemu jest nieużywanie żadnej zmiennej lokalnej do przechowywania instancji obiektów w procedurach, które można wykonać GetRef.

Zamiast zmiennych niejawnych lub jawnych, użycie lokalnego obiektu słownika (lub globalnego, jeśli nie ma rekurencji) do przechowywania instancji obiektów i wywoływanie ich przez ten słownik działa.

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

Wydaje się, że warto używać, jeśli masz skrypt, który nie jest zbyt skomplikowany.

Kul-Tigin
źródło
1
Właśnie go przetestowałem i mogę potwierdzić, że działa na moim komputerze. Oznaczę to jako rozwiązanie. To jest najlepsze, dopóki Microsoft nie zapewni poprawki (zakładając, że uznają to za błąd) .
Lieven Keersmaekers