โชคดีที่คุณชี้ให้เห็นว่าCOMPACT Mono build ใช้ generational GC (ในทางตรงข้ามกับ Microsoft เช่น WinMo / WinPhone / XBox ที่เพิ่งรักษารายชื่อไว้)
หากเกมของคุณง่าย GC ควรจัดการได้ดี แต่นี่คือตัวชี้บางอย่างที่คุณอาจต้องการตรวจสอบ
การเพิ่มประสิทธิภาพก่อนวัยอันควร
ก่อนอื่นให้แน่ใจว่านี่เป็นปัญหาสำหรับคุณจริง ๆ ก่อนที่จะลองแก้ไข
การรวมประเภทอ้างอิงราคาแพง
คุณควรพูประเภทอ้างอิงที่คุณสร้างบ่อยหรือมีโครงสร้างที่ลึก ตัวอย่างของแต่ละคนจะเป็น:
- สร้างมักจะ: เป็น
Bullet
วัตถุในเกมกระสุนนรก
- โครงสร้างที่ลึก: แผนผังการตัดสินใจสำหรับการนำ AI ไปใช้
คุณควรใช้ a Stack
เป็นกลุ่มของคุณ (ต่างจากการใช้งานส่วนใหญ่ที่ใช้ a Queue
) เหตุผลนี้เป็นเพราะStack
ถ้าคุณกลับวัตถุไปยังสระและสิ่งอื่นคว้ามันทันที; มันจะมีโอกาสสูงที่จะอยู่ในหน้าเพจที่ใช้งานอยู่หรือแม้กระทั่งในแคช CPU หากคุณโชคดี มันเร็วกว่านิดหน่อย นอกจากนี้ จำกัด ขนาดพูลของคุณทุกครั้ง (เพียงไม่สนใจ 'เช็คอิน' หากเกินขีด จำกัด ของคุณ)
หลีกเลี่ยงการสร้างรายการใหม่เพื่อล้างพวกเขา
อย่าสร้างใหม่List
เมื่อคุณตั้งใจจะทำClear()
มันจริงๆ คุณสามารถใช้อาเรย์แบ็คเอนด์อีกครั้งและบันทึกภาระการจัดสรรและการคัดลอกอาเรย์ เช่นเดียวกับการลองและสร้างรายการที่มีความจุเริ่มต้นที่มีความหมาย (โปรดจำไว้ว่านี่ไม่ จำกัด เพียงแค่ความสามารถเริ่มต้น) - มันไม่จำเป็นต้องแม่นยำเพียงแค่การประมาณ นี้ควรนำไปใช้กับพื้นชนิดคอลเลกชันใด ๆ - LinkedList
ยกเว้น
ใช้โครงสร้างอาร์เรย์ (หรือรายการ) ที่เป็นไปได้
คุณจะได้รับประโยชน์เล็กน้อยจากการใช้งาน structs (หรือประเภทค่าโดยทั่วไป) ถ้าคุณผ่านมันไปมาระหว่างวัตถุ ตัวอย่างเช่นในระบบอนุภาค 'ดี' ส่วนใหญ่อนุภาคแต่ละอันจะถูกเก็บไว้ในอาเรย์ขนาดใหญ่: อาเรย์และและดัชนีถูกส่งผ่านไปรอบ ๆ แทนที่จะเป็นอนุภาค เหตุผลที่มันใช้งานได้ดีเพราะเมื่อ GC ต้องการรวบรวมอาร์เรย์มันสามารถข้ามเนื้อหาทั้งหมดได้ (มันเป็นอาร์เรย์ดั้งเดิม - ไม่มีอะไรให้ทำที่นี่) ดังนั้นแทนที่จะมองหาวัตถุ 10,000 ชิ้น GC ต้องการเพียงแค่ดู 1 อาร์เรย์: รับมาก! อีกครั้งนี้จะทำงานเฉพาะกับประเภทค่า
หลังจาก RoyT ให้ข้อเสนอแนะที่เป็นไปได้และสร้างสรรค์บางอย่างฉันรู้สึกว่าฉันจำเป็นต้องขยายเพิ่มเติม คุณควรใช้เทคนิคนี้เฉพาะเมื่อคุณจัดการกับเอนทิตีจำนวนมาก (หลายพันถึงหลายหมื่น) นอกจากนี้ยังต้องเป็นโครงสร้างที่ไม่ต้องมีฟิลด์ชนิดการอ้างอิงใด ๆ และต้องอาศัยอยู่ในอาร์เรย์อย่างชัดเจนพิมพ์ ตรงกันข้ามกับความคิดเห็นของเขาเรากำลังวางมันลงในอาเรย์ซึ่งน่าจะเป็นสนามในชั้นเรียน - ซึ่งหมายความว่ามันจะทำให้กองขึ้น (เราไม่ได้พยายามหลีกเลี่ยงการจัดสรรฮีป - เพียง แต่หลีกเลี่ยงการทำงานของ GC) เราใส่ใจจริงๆคือความจริงที่ว่ามันเป็นหน่วยความจำต่อเนื่องที่มีค่ามากมายที่ GC สามารถมองเห็นในการO(1)
ดำเนินการแทนการO(n)
ดำเนินการ
นอกจากนี้คุณยังควรจัดสรรอาร์เรย์เหล่านี้ใกล้เคียงกับการเริ่มต้นใช้งานของคุณเป็นไปได้ที่จะลดโอกาสของการกระจายตัวที่เกิดขึ้นหรือการทำงานที่มากเกินไปเป็น GC พยายามที่จะย้ายชิ้นเหล่านี้ไปรอบ ๆ (และพิจารณาการใช้รายการไฮบริดที่เชื่อมโยงแทนในตัวList
ชนิด )
GC.Collect ()
นี่เป็นวิธีที่ดีที่สุดในการถ่ายภาพตัวเองด้วยเท้า (ดู: "การพิจารณาประสิทธิภาพ") ด้วย GC ทั่วไป คุณควรเรียกมันว่าเมื่อคุณได้สร้างEXTREMEปริมาณขยะ - และตัวอย่างหนึ่งที่ที่อาจจะมีปัญหาเป็นเพียงหลังจากที่คุณได้โหลดเนื้อหาสำหรับระดับ - และแม้แล้วคุณควรอาจจะเป็นเพียงการเก็บรวบรวมรุ่นแรก ( GC.Collect(0);
) หวังว่าจะป้องกันการส่งเสริมวัตถุไปยังรุ่นที่สาม
IDisposable และ Nulling ภาคสนาม
มันจะคุ้มค่ากับช่องว่างเมื่อคุณไม่ต้องการวัตถุอีกต่อไป เหตุผลอยู่ในรายละเอียดของวิธีการทำงานของ GC: จะลบเฉพาะวัตถุที่ไม่ได้ถูกรูท (เช่นการอ้างอิง) แม้ว่าวัตถุนั้นจะไม่ได้ทำการรูทเพราะวัตถุอื่นที่ถูกลบในคอลเลกชันปัจจุบัน ( หมายเหตุ:ขึ้นอยู่กับ GC รสชาติที่ใช้ - บางคนล้างโซ่จริง ๆ ) นอกจากนี้หากวัตถุมีชีวิตรอดจากการสะสมมันจะได้รับการเลื่อนตำแหน่งไปยังรุ่นต่อไปในทันที - ซึ่งหมายความว่าวัตถุใด ๆ ที่วางอยู่ในทุ่งจะได้รับการเลื่อนตำแหน่งในระหว่างการรวบรวม แต่ละรุ่นที่ต่อเนื่องมีราคาแพงกว่าในการรวบรวม (และเกิดขึ้นไม่บ่อย)
นำตัวอย่างต่อไปนี้:
MyObject (G1) -> MyNestedObject (G1) -> MyFurtherNestedObject (G1)
// G1 Collection
MyNestObject (G2) -> MyFurtherNestedObject (G2)
// G2 Collection
MyFurtherNestedObject (G3)
หากMyFurtherNestedObject
มีวัตถุหลายเมกะไบต์คุณสามารถรับประกันได้ว่า GC จะไม่มองมันนานนัก - เพราะคุณเลื่อนขั้นเป็น G3 โดยไม่ได้ตั้งใจ ตัดกันด้วยตัวอย่างนี้:
MyObject (G1) -> MyNestedObject (G1) -> MyFurtherNestedObject (G1)
// Dispose
MyObject (G1)
MyNestedObject (G1)
MyFurtherNestedObject (G1)
// G1 Collection
รูปแบบ Disposer ช่วยให้คุณตั้งค่าวิธีที่คาดเดาได้ในการขอให้วัตถุล้างเขตข้อมูลส่วนตัวของพวกเขา ตัวอย่างเช่น:
public class MyClass : IDisposable
{
private MyNestedType _nested;
// A finalizer is only needed IF YOU CONTROL UNMANAGED RESOURCES
// ~MyClass() { }
public void Dispose()
{
_nested = null;
}
}