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

คู่มือเกมแลค › L10 หน่วยความจำ

GC thrashing (heap เหลือที่ว่างไม่พอ) GC thrashing (heap nearly full)

ID สาเหตุ mem-gc-thrash · ผู้รับผิดชอบหลัก พัฒนาเซิร์ฟเวอร์ (ทีมพัฒนาเกม) · ร่วมกับ อินฟราเซิร์ฟเวอร์ (ทีมอินฟรา)

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

เมื่อข้อมูลที่ยังใช้อยู่ (live data) เข้าใกล้ขีดจำกัดของ heap แม้ GC ทำงานก็แทบไม่มีอะไรให้เก็บคืน GC จึงวนทำงานซ้ำไม่หยุด

ทำไม ผู้เล่นเพิ่มขึ้นช่วงอีเวนต์หรือหน่วยความจำรั่ว ทำให้ข้อมูลที่ยังใช้อยู่เต็มจนใกล้ขีดจำกัดของ heap → ผลคือ GC เก็บคืนได้นิดเดียวจึงต้องทำ Full GC อีกทันที และ GC ใช้ CPU ไปเกือบทั้งหมด → บนหน้าจอ ทั้งเซิร์ฟเวอร์เป็นสโลว์โมชั่นสลับกับค้างซ้ำ ๆ อยู่หลายนาที แล้วปิดตัวเพราะหน่วยความจำไม่พอ

อาการ
สโลว์โมชั่น, ค้าง, หลุด
ปัจจัย
การหยุดชะงัก
ใครเจอ
ทั้งเซิร์ฟเวอร์
เกิดเมื่อไร
ช่วงพีคหัวค่ำ, ตอนคนแห่มารวมกัน, ยิ่งเปิดไว้นานยิ่งเป็น
ผู้รับผิดชอบ
ผู้รับผิดชอบหลัก พัฒนาเซิร์ฟเวอร์ (ทีมพัฒนาเกม) · ร่วมกับ อินฟราเซิร์ฟเวอร์ (ทีมอินฟรา)
งานฝั่งทีมพัฒนาเกม
ตั้ง heap ให้ใหญ่กว่าข้อมูลที่ยังใช้อยู่ตอนพีคอย่างเหลือเฟือ (ปกติ 2 เท่าขึ้นไป), ลดข้อมูลที่ถูกอ้างอิงไว้นานและลดการรั่ว
งานฝั่งทีมอินฟรา
ตั้ง alert ตามสัดส่วนเวลาที่ใช้ไปกับ GC, รีสตาร์ตให้เร็วแทนการฝืนรันต่อ, ใช้อินสแตนซ์ที่มีหน่วยความจำเหลือพอให้ขยาย heap ได้
ตัวเลขที่ควรรู้
ถ้า GC ใช้เวลาเกิน 10% ของเวลารันทั้งหมด มักถือเป็นสัญญาณอันตราย GC บางตัวของ Java จะแจ้งข้อผิดพลาดหน่วยความจำไม่พอ ถ้าใช้เวลา 98% ไปกับ GC แต่แทบเก็บคืนอะไรไม่ได้
บนกราฟ
ชนเพดานแล้วแบนราบ · heap หลัง GC, สัดส่วนเวลาที่ใช้ไปกับ GC
จุดที่ต้องดู
heap ที่เหลือหลัง GC ใกล้ heap สูงสุดแค่ไหน และสัดส่วนเวลาที่ใช้ไปกับ GC Java ดู “หลัง GC (ขนาด heap)” ในบรรทัดของ -Xlog:gc และความถี่ของบรรทัด Pause Full, .NET ดู dotnet-counters (.NET 8 ลงไปคือ % Time in GC since last GC, ตั้งแต่ .NET 9 คือค่าที่เพิ่มขึ้นของ dotnet.gc.pause.time), Go ดูช่วงห่างระหว่างบรรทัดของ GODEBUG=gctrace=1
สัญญาณว่าใช่
แม้หลัง GC heap ก็ยังเหลือใกล้ค่าสูงสุด Full GC ทำงานติดกันหลายครั้ง และสัดส่วนเวลาที่ใช้ไปกับ GC สูงกว่าปกติมาก (ปกติเกิน 10%) ระหว่างนั้นทิกของทั้งเซิร์ฟเวอร์ช้าลงไปด้วย
สัญญาณว่าไม่ใช่
heap หลัง GC ยังมีที่ว่างแต่หยุดนานอย่างเดียว: น่าจะเป็นเรื่องประเภทหรือการตั้งค่า GC (mem-gc)
วิธีตรวจ
ใช้เครื่องมือฝั่งอินฟรา (ไม่ต้องใช้โค้ดเกม)

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

  1. The Parallel Collector Oracle
    parallel GC จะแจ้ง OutOfMemoryError ถ้าใช้เวลาเกิน 98% ของเวลาทั้งหมดไปกับ GC แล้วเก็บคืน heap ได้น้อยกว่า 2%
  2. Garbage-First Garbage Collector Tuning Oracle
    ค่าเริ่มต้นของ G1 (GCTimeRatio=12) จะกำหนดขนาด heap ให้เวลา GC อยู่ที่ประมาณไม่เกิน 8% ของเวลาทั้งหมด, Full GC ที่เกิดจาก heap ถูกใช้สูงเกินไปหาได้จาก Pause Full (G1 Compaction Pause) ใน log
  3. A Guide to the Go Garbage Collector Go
    ค่าเริ่มต้น GOGC=100 ทำให้ heap เป้าหมายประมาณ 2 เท่าของ heap ที่ยังใช้อยู่, ถ้าชนขีดจำกัดหน่วยความจำ GC จะทำงานไม่หยุดจนเกิด thrashing, ใช้ GODEBUG=gctrace=1 แสดงผลการติดตาม GC
  4. Garbage Collector Implementation Oracle
    บรรทัดของ -Xlog:gc แสดงประเภท GC (Pause Young, Pause Full), “ปริมาณที่ใช้ก่อน GC->ปริมาณที่ใช้หลัง GC (ขนาด heap)” และเวลาที่หยุด
  5. dotnet-counters diagnostic tool .NET
    ตั้งแต่ .NET 9 แสดงเป็น dotnet.gc.pause.time ส่วน .NET 8 ลงไปแสดงเป็น % Time in GC since last GC

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

ชั้นเดียวกัน: L10 หน่วยความจำ

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

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