ปริมาณการใช้หน่วยความจำของ GetRef (การรวบรวมขยะ) เปลี่ยนแปลงด้วย KB4525236


11

เราพบปัญหาหน่วยความจำไม่เพียงพอหลังจากติดตั้งKB4525236ใน Windows 2016 Servers / Windows 10 Clients GetRefแก้ไขการรักษาความปลอดภัยนี้ดูเหมือนว่าจะมีการเปลี่ยนแปลงช่วงเวลาที่หน่วยความจำที่เก็บขยะเมื่อเรียกฟังก์ชั่นผ่าน

ก่อน KB4525236

แต่ละอินสแตนซ์ที่สร้างขึ้นในฟังก์ชั่นที่เรียกใช้ผ่านGetRefได้รวบรวมขยะทันทีที่ตัวแปรอินสแตนซ์ถูกตั้งค่าเป็นnothing

โพสต์ KB4525236

เช่นกันสร้างขึ้นในฟังก์ชั่นที่เรียกว่าผ่านGetRefยังคงอยู่ในหน่วยความจำและเก็บขยะเฉพาะเมื่อเสร็จสมบูรณ์ทั้งฟังก์ชั่น เมื่อสร้างอินสแตนซ์ในการวนซ้ำสิ่งนี้สามารถเพิ่มและนำไปสู่หน่วยความจำไม่เพียงพอโดยเฉพาะอย่างยิ่งในกระบวนการ 32 บิต

คำถาม

  • เราไม่พบสิ่งที่เกี่ยวข้องทางออนไลน์ดังนั้นเราจึงต้องการได้รับการยืนยันจากผู้อื่นที่ประสบปัญหาเดียวกัน
    แก้ไขรอยขีดข่วนที่: นี่เป็นปัญหาเดียวกัน แต่ยังไม่มีวิธีแก้ปัญหา ณ
    (vbscript.dll class_terminate bug ตั้งแต่ KB4524570 (12 พฤศจิกายน 2019) Windows 10 1903)
  • ถ้าใครสามารถตรวจสอบและรู้วิธีแก้ปัญหาที่ใช้การได้นั่นจะยอดเยี่ยม

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 ของอินสแตนซ์และพวกเขาให้ cumulating หน่วยความจำจนกว่าจะสิ้นสุดลงในขณะที่ในอดีตที่ผ่านมาพวกเขาเป็นอิสระในขณะที่รันวงใน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

คำตอบ:


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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.