한국어English日本語简体中文繁體中文DeutschไทยTiếng ViệtРусскийPortuguês (Brasil)EspañolBahasa Indonesia

คู่มือเกมแลค › L1 โปรเซสเกมฝั่งไคลเอนต์

GC ฝั่งไคลเอนต์ Client GC (Unity C#, Unreal, Lua)

ID สาเหตุ cg-gc · ผู้รับผิดชอบหลัก พัฒนาไคลเอนต์ (ทีมพัฒนาเกม)

เปิดการ์ดในฉบับหลักที่มีภาพและการทดลอง →

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

ทำไม สร้าง string, array และ list ชั่วคราวแล้วทิ้งทุกเฟรม → ผลคือ เมื่อ garbage สะสมมากพอ GC จะหยุดเมนเธรดเพื่อเก็บคืน → บนหน้าจอ กระตุกเป็นจังหวะทุกไม่กี่วินาทีถึงหลายสิบวินาที

อาการ
กระตุก, ค้าง
ปัจจัย
การหยุดชะงัก
ใครเจอ
เราคนเดียว
เกิดเมื่อไร
เป็นรอบสม่ำเสมอ, ตอนคนแห่มารวมกัน
ผู้รับผิดชอบ
ผู้รับผิดชอบหลัก พัฒนาไคลเอนต์ (ทีมพัฒนาเกม)
งานฝั่งทีมพัฒนาเกม
ลดการจัดสรรหน่วยความจำ (เลี่ยงการต่อ string, LINQ และ lambda capture), ใช้ object pool, เปิด incremental GC ไว้ (เป็นค่าเริ่มต้นตั้งแต่ Unity 2020), สั่ง GC ล่วงหน้าในจังหวะที่หยุดได้ เช่น หน้าโหลด
ตัวเลขที่ควรรู้
ปกติครั้งละหลักหน่วย ms ถึง 100 ms ส่วนมือถือสเปกต่ำหรือเกมที่ใช้หน่วยความจำมากอาจนานกว่านั้น (ในการทดลองราว 150–170 ms) GC ของ Unity ตรวจทั้ง heap ทุกครั้งที่ทำงาน ยิ่งเกมใช้หน่วยความจำมากก็ยิ่งนาน
บนกราฟ
พุ่งเป็นรอบ · เฟรมไทม์, เวลาที่ GC ทำงาน
จุดที่ต้องดู
ดู marker GC.Collect และ GC.Alloc ใน Unity Profiler บน development build ส่วน Unreal ดู stat GC และ stat Hitches (บันทึกเฟรมที่เกินเวลาที่ตั้งไว้ใน t.HitchFrameTimeThreshold ลง log)
สัญญาณว่าใช่
ทุกเฟรมที่พุ่งมีช่วง GC.Collect ยาวใกล้เคียงกับช่วงที่พุ่ง และเกิดเป็นรอบสม่ำเสมอทุกไม่กี่วินาทีถึงหลายสิบวินาที ในที่ที่คนเยอะ GC.Alloc ต่อเฟรมเพิ่มขึ้น
สัญญาณว่าไม่ใช่
เฟรมที่พุ่งไม่มีช่วง GC: น่าจะเป็น “โหลดแบบ synchronous และคอมไพล์ shader บนเมนเธรด” หรือ “ภาระการเรนเดอร์ตัวละครจำนวนมาก”
วิธีตรวจ
ต้องมี log หรือเมตริกจากเซิร์ฟเวอร์/ไคลเอนต์เกม
รายละเอียดเพิ่มเติม
พบบ่อยในไคลเอนต์ที่เขียนด้วย C# อย่าง Unity ตัวการหลักคือโค้ดที่สร้าง string ของ combat log, ตัวเลขดาเมจ และข้อความ UI ขึ้นใหม่ทุกเฟรม ถ้ากระตุกเฉพาะที่ที่คนเยอะ แปลว่ามีโค้ดที่สร้าง garbage เพิ่มตามจำนวนผู้เล่น incremental GC แบ่งเก็บทีละนิดในแต่ละเฟรม (ค่าเริ่มต้นของ Unity คือ 3 ms) แต่ถ้าสร้าง garbage เร็วกว่าที่เก็บทัน สุดท้ายก็ต้องหยุดเก็บรวดเดียวอยู่ดี Unreal Engine ก็มี GC ของตัวเองที่เก็บกวาด game object ที่ไม่ได้ใช้ ค่าจะต่างกันไปตามเวอร์ชันเอนจินและการตั้งค่า แต่ค่าเริ่มต้นจะทำงานราวทุก 1 นาที จึงอาจเกิดอาการหยุดแวบทุก 1 นาทีได้ ไคลเอนต์ที่เขียนกฎของเกมด้วยสคริปต์อย่าง Lua ยังมี GC ของสคริปต์นั้นทำงานแยกอีกชุดหนึ่ง

แหล่งอ้างอิง

  1. Garbage collection modes Unity
    ค่าเริ่มต้นคือ incremental GC ที่แบ่งเก็บในหลายเฟรม ถ้าปิดไว้ เมนเธรดจะหยุดระหว่างตรวจทั้ง heap และอาจนานถึงหลายร้อย ms
  2. Scripting.GarbageCollector.CollectIncremental Unity
    เป้าหมายเริ่มต้นของเวลาที่ incremental GC ใช้ต่อครั้ง (time slice) คือ 3 ms (incrementalTimeSliceNanoseconds)
  3. Garbage Collection Settings in the Unreal Engine Project Settings Epic Games
    การตั้งค่าที่ทำให้ GC ของ Unreal ทำงานตามช่วงเวลาที่กำหนด (Time Between Purging Pending Kill Objects หน่วยเป็นวินาที) เอกสารนี้ไม่ได้ระบุตัวเลขค่าเริ่มต้น
  4. Profiler markers reference Unity
    GC.Collect: ช่วงที่โค้ดของโปรแกรมหยุดระหว่าง garbage collection (ไม่ถึง 1 ms ไปจนถึงหลายร้อย ms), GC.Alloc: การจัดสรร managed heap
  5. Stat Commands in Unreal Engine Epic Games
    stat GC (สถิติ garbage collection), stat Hitches (บันทึกเฟรมที่เกิน t.HitchFrameTimeThreshold ลง log)

สาเหตุที่ควรดูประกอบ

ชั้นเดียวกัน: L1 โปรเซสเกมฝั่งไคลเอนต์

สาเหตุจากชั้นอื่นที่ทำให้เกิดอาการเดียวกัน (กระตุก)

ดูการ์ดในฉบับหลักที่มีภาพและการทดลอง