OutOfMemoryException บนเครื่องเฉพาะเมื่อทำการทดสอบ

เรามีการทดสอบการทดสอบ NUnit ที่กำลังประสบปัญหา OutOfMemoryExceptions บนเครื่องใดเครื่องหนึ่ง

หลังจากการตรวจสอบ ดูเหมือนว่าไม่ใช่ปัญหาด้านหน่วยความจำ แต่เป็นปัญหาด้านการจัดการ (เรากำลังจัดสรรออบเจ็กต์บิตแมปมากเกินไปและไม่ปล่อยออก)

ปัญหาคือว่าสิ่งนี้ทำงานได้อย่างสมบูรณ์บนเครื่องใดเครื่องหนึ่ง ในขณะที่ล้มเหลวด้วยข้อผิดพลาดนี้ในเครื่องอื่น

  1. เครื่องที่ล้มเหลวคือ Hyper-V VM พร้อม Windows7 x64 (ram 6 GB)
  2. Working Machine เป็นเครื่องจริง Windows XP (ram 2 GB)

ฉันรู้ว่าทางออกที่ดีที่สุดคือการล้างโค้ดเพื่อกำจัดออบเจ็กต์ Bitmap ใด ๆ แต่ฉันสนใจที่จะรู้ว่าเหตุใด 2 เครื่องนี้จึงมีพฤติกรรมที่แตกต่างกันเมื่อรันโค้ดเดียวกัน


person lysergic-acid    schedule 30.09.2013    source แหล่งที่มา
comment
เฟรมเวิร์ก .NET อาจจะเหมือนกัน แต่ระบบปฏิบัติการพื้นฐานไม่ใช่ ทรัพยากรเช่นบิตแมปยังคงได้รับการจัดการโดยระบบปฏิบัติการ Windows 7 จัดการทรัพยากรแตกต่างจาก Windows XP จึงไม่น่าแปลกใจที่คุณจะได้รับผลลัพธ์ที่แตกต่างกันใน Windows เวอร์ชันต่างๆ   -  person helb    schedule 30.09.2013
comment
จำนวนจุดจับที่อาจรั่วไหลก่อนที่ Windows จะปฏิเสธที่จะออกอีกสามารถกำหนดค่าได้ บางทีเครื่องใดเครื่องหนึ่งอาจมีการกำหนดค่าแตกต่างออกไป   -  person Eric Lippert    schedule 30.09.2013
comment
ขอบคุณ @เอริค คุณรู้หรือไม่ว่าสิ่งนี้สามารถควบคุมได้จากที่ไหน?   -  person lysergic-acid    schedule 30.09.2013
comment
@ lysergic-acid: นี่คือไซต์คำถามและคำตอบ ถามคำถามเป็นคำถาม!   -  person Eric Lippert    schedule 30.09.2013


คำตอบ (2)


อ่านสิ่งนี้: http://blogs.technet.com/b/markrussinovich/archive/2010/02/24/3315174.aspx

คุณจะพบตารางความแตกต่างระหว่าง Windows เวอร์ชันต่างๆ ที่เกี่ยวข้องกับฮีป GDI คำตอบสั้นๆ: XP = ขีดจำกัด 3Mb, Win7R2x64 = ขีดจำกัด 20Mb RAM ฟรีไม่สำคัญ สิ่งเหล่านี้เป็นข้อจำกัดที่ยาก

person jlew    schedule 30.09.2013
comment
สิ่งนี้ไม่สอดคล้องกับความจริงที่ว่าบน XP มันไม่ขัดข้องและใน Win7 ก็ไม่ขัดข้อง :( - person lysergic-acid; 30.09.2013
comment
อาจสาบานได้ว่าเงื่อนไขของคุณตรงกันข้ามกับที่เป็นอยู่ตอนนี้ - person jlew; 30.09.2013

ไม่น่าเป็นไปได้ที่ Windows จะยอมให้คุณรั่วไหล 10,000 แฮนเดิลก่อนที่มันจะเกิดความบ้าๆบอ ๆ เกี่ยวกับวิธีการทำงานของโปรแกรมของคุณและปฏิเสธที่จะให้คุณจัดสรรเพิ่ม เมื่อถึงเวลานั้น คุณได้ใช้พื้นที่หน่วยความจำเสมือนจำนวนมหาศาลสำหรับข้อมูลพิกเซลในบิตแมป ตัวรวบรวมขยะถูกจัดเก็บไว้ในหน่วยความจำที่ไม่มีการจัดการ พื้นที่ VM ที่ไม่ได้รับการเผยแพร่เว้นแต่คุณจะเรียก Dispose() หรือตัวรวบรวมขยะจะดูแลมันโดยการเรียกใช้ตัวสรุป

โดยทั่วไป GC จะไม่ทำงานให้เสร็จ คลาสบิตแมปเป็นวัตถุขนาดเล็กมาก ไม่ใหญ่พอที่จะทริกเกอร์ GC ด้วยตัวเอง คุณจะต้องจัดสรรประมาณ 60,000 รายการจึงจะเรียก GC ได้ คุณจะไม่ไปถึงที่นั่น พื้นที่ VM ของคุณหมดก่อน เว้นแต่บิตแมปจะมีขนาดเล็กมาก จัดการต่อไป การเรียก Dispose() เป็นทางเลือก แต่นั่นจะไม่เป็นทางเลือกสำหรับบิตแมปเนื่องจากตัวสรุปไม่สามารถทำงานให้เสร็จทันเวลา

จำนวน RAM ไม่มีบทบาทใด ๆ ในเรื่องนี้ โปรแกรม. NET มักจะระเบิดโดยไม่สามารถหาช่องโหว่ในพื้นที่ที่อยู่ VM ที่ใหญ่พอที่จะพอดีกับขนาดที่ร้องขอ ปัญหาเกี่ยวกับบิตแมปก็มักจะต้องมีรูขนาดใหญ่ เพียงใช้ DLL ที่โหลดไปยังที่อยู่ฐานที่น่าอึดอัดใจเพื่อตัดรูขนาดใหญ่ที่สวยงามออกเป็นสองส่วน ไม่เช่นนั้นปัญหาจะแก้ไขได้ง่ายเพียงแค่ตั้งค่าแพลตฟอร์มเป้าหมายของโปรแกรมเป็น AnyCPU โปรแกรมทดสอบมีค่าการกำหนดค่าสำหรับสิ่งนั้น ใช้งานได้บนเครื่อง Win7 นั้น แต่แน่นอนว่านั่นไม่ใช่เหตุผลที่ถูกต้องที่จะข้ามการโทร Dispose()

person Hans Passant    schedule 30.09.2013