Stack Overflow คือ เว็บบอร์ด programmer ระดับตำนาน เฮ้ย อาการที่โปรแกรมเกิดการแครช ( Crash ) หรือพังลงมา เนื่องจากมีการใช้งานพื้นที่ Stack Memory จนล้นทะลุขีดจำกัดที่ระบบปฏิบัติการหรือคอมไพเลอร์กำหนดไว้ครับ ลองจินตนาการถึงการซ้อนจานใบใหม่ทับไปเรื่อย ๆ ถ้าซ้อนสูงเกินไปจนชนเพดาน จานก็จะล้มครืนลงมา นั่นคือสิ่งที่เกิดขึ้นกับหน่วยความจำเลยครับ
สาเหตุหลักที่ทำให้เกิด Stack Overflow
การเรียกฟังก์ชันซ้ำตัวเองแบบไม่รู้จบ ( Infinite Recursion )
นี่คือสาเหตุยอดฮิตอันดับหนึ่งครับ ปกติเวลาฟังก์ชันถูกเรียกใช้งาน ระบบจะสร้างบล็อกข้อมูลที่เรียกว่า Stack Frame ( เก็บพารามิเตอร์และตัวแปรโลคัล ) วางซ้อนทับกันใน Stack ถ้าระบุเงื่อนไขการหยุดไม่ดี หรือลืมใส่จุดสิ้นสุด ( Base Case ) ฟังก์ชันจะเรียกตัวเองไปเรื่อยๆ ทำให้ Stack Frame ถูกสร้างซ้อนกันจนล้น ลองดูตัวอย่างโค้ด C# สั้น ๆ ครับ เมื่อโค้ดนี้รัน มันจะเอาข้อมูลของ PrintNumber ไปสุมไว้ใน Stack รัว ๆ จนกระทั่ง Stack เต็ม และโยน Error StackOverflowException ออกมาทำให้โปรแกรมดับไปเลยครับ
public void PrintNumber(int n)
{
// ลืมเขียนเงื่อนไขเพื่อหยุด (เช่น if (n <= 0) return;)
Console.WriteLine(n);
PrintNumber(n - 1); // ฟังก์ชันเรียกตัวเองซ้ำไปเรื่อยๆ ไม่มีวันจบ
}
การประกาศตัวแปรขนาดใหญ่มากไว้ใน Stack
แม้จะไม่เจอบ่อยเท่ากรณีแรก แต่ถ้าเราพยายามจองพื้นที่ตัวแปรโลคัลที่มีขนาดใหญ่เกินไป เช่น การสร้าง Array พื้นฐานขนาดมหาศาลไว้ในฟังก์ชัน ( ซึ่งจะถูกบังคับให้อยู่ใน Stack ) แทนที่จะใช้ new เพื่อโยนไปเก็บไว้ใน Heap ก็อาจทำให้ Stack ที่มีพื้นที่จำกัด ( มักจะแค่ไม่กี่ Megabytes ) เต็มได้ทันที
วิธีป้องกัน
- ตรวจสอบจุดสิ้นสุด ( Base Case ) เสมอ: หากต้องเขียน Recursive Function ต้องแน่ใจว่ามีเงื่อนไข
returnเพื่อให้ฟังก์ชันหยุดเรียกตัวเองและเริ่ม Pop ข้อมูลออกจาก Stack ได้ - เปลี่ยนไปใช้ Loop: ในบางกรณีที่เสี่ยงต่อการเกิด Stack Overflow สูง การเปลี่ยนไปใช้
forหรือwhileloop แทนการทำ Recursion จะปลอดภัยกว่า เพราะ Loop ไม่ได้สร้าง Stack Frame ใหม่ทุกรอบการทำงาน - โยนของชิ้นใหญ่ไป Heap: ถ้าต้องจัดการข้อมูลขนาดใหญ่มากๆ ให้จองพื้นที่แบบไดนามิก (ใช้ Reference Types) เพื่อให้ไปหนักที่ Heap แทนครับ
เกร็ดน่ารู้
เว็บไซต์ถามตอบสำหรับโปรแกรมเมอร์ชื่อดังอย่าง StackOverflow.com ก็ตั้งชื่อตาม Error ตัวนี้นี่แหละครับ เพราะเป็นปัญหาคลาสสิกที่โปรแกรมเมอร์ทุกคนต้องเคยเจอ
อ่านเพิ่มเติม
About the author