CodeQuiz EP.31 - Stack กับ Heap ใน memory ต่างกันยังไง

https://storage.googleapis.com/locth-web/loc_logo1_4bfbd63526/loc_logo1_4bfbd63526.svg

ทีมงาน Leagues of Code TH

เผยแพร่เมื่อ

CodeQuiz EP.31 - Stack กับ Heap ใน memory ต่างกันยังไง

สาระสำคัญ

Memory ของคอมแบ่งเป็น 2 โซน คือ Stack เหมือนกองกระดาษบนโต๊ะ (เร็ว มีระเบียบ ขนาดเล็ก ใช้กับ function calls และ local variables, cleanup อัตโนมัติ) และ Heap เหมือนห้องเก็บของรก ๆ (ใหญ่ ยืดหยุ่น ช้ากว่า ใช้กับ object ขนาดใหญ่หรือของที่ต้อง share ข้าม function ต้องจัดการเองใน C/C++ หรือพึ่ง Garbage Collector ใน Python/Java/JS) Stack overflow คือ recursion ลึกเกินจน Stack เต็ม ส่วน Memory leak คือทิ้งของไว้บน Heap แล้วลืมลบ

เคยได้ยินคำว่า Stack overflow ป่ะ ใช่ ๆ ชื่อเว็บที่เราเข้าไปก๊อปโค้ดมาแก้ bug นั่นแหละ แต่ Stack overflow จริง ๆ ในโลก programming คือ error อย่างนึงที่หลายคนเจอตอนเขียน recursion (function ที่เรียกตัวเอง) แล้ว Stack คืออะไรอะ ทำไมมันต้อง overflow ด้วยล่ะ

วันนี้พี่จะมาเล่าเรื่อง memory ของคอมว่ามี 2 โซนใหญ่ ๆ ที่ชื่อ Stack กับ Heap หน้าตาและการใช้งานต่างกันเยอะมาก แล้วทำไม junior dev ต้องรู้จักไว้ก่อนถูกสัมภาษณ์ถาม

เปิดด้วยภาพในหัว: "กองกระดาษ" กับ "ห้องเก็บของ"

เปิดด้วยภาพในหัว: "กองกระดาษ" กับ "ห้องเก็บของ"
เปิดด้วยภาพในหัว: "กองกระดาษ" กับ "ห้องเก็บของ"

Stack คือ กองกระดาษบนโต๊ะ ใส่กระดาษทับลงไปได้ (push) หยิบกระดาษออกได้แค่ใบบนสุด (pop) อยากหาใบที่อยู่กลาง ๆ อะ อด ต้องโล๊ะออกทีละใบจากบน คอนเซปต์นี้เรียกว่า LIFO ย่อจาก Last In First Out คือใส่ทีหลัง หยิบก่อน

Heap คือ ห้องเก็บของรก ๆ หรือกองตู้ MUJI ที่ทุกอย่างกองรวมกันโดยไม่มีระเบียบ โยนของเข้าไปตรงไหนก็ได้ มีพื้นที่ก็เก็บ แต่จะหยิบของกลับ ต้องจำว่าเอาไปวางไว้ตรงไหน คือต้องมี pointer (เลขชี้ตำแหน่งใน memory เหมือนเลขล็อกเกอร์) ไม่งั้นหาทั้งวันก็ไม่เจอ

📦 Stack คือเร็ว มีระเบียบ จำกัดขนาด 📚 Heap คือยืดหยุ่น ใหญ่ได้ตามใจ แต่ช้ากว่า

ใช้ตอนไหนเหรอ

ทุกครั้งที่น้องเรียก function คอมจะแอบเอา local variables ของ function นั้นไปวางไว้บน Stack พอ function จบ คอมก็ pop ทุกอย่างทิ้งทันที ไม่ต้องสั่ง ไม่ต้องคิด เป็น auto-cleanup ฟรี เริ่ดป่ะ

แต่ถ้าน้องสร้าง object ขนาดใหญ่ ๆ หรืออะไรที่ต้อง share ข้ามหลาย function เช่น array ขนาด 1 ล้านตัว หรือ class instance ที่จะใช้ตลอดโปรแกรม มันต้องไปอยู่ Heap เพราะ Stack มีขนาดจำกัด ปกติประมาณ 1 ถึง 8 MB (เมกะไบต์ คือ 1,048,576 bytes ขนาดเท่ารูปถ่ายเล็ก ๆ ใบนึง) เก็บของใหญ่ไม่ไหวอะ

โค้ดจริง ๆ หน้าตายังไง

ใน C++ น้องบอกได้เลยว่าจะให้ของอยู่ Stack หรือ Heap

1
2
int x = 5; // Stack คือ auto cleanup
int* y = new int(5); // Heap คือต้อง delete y; เอง ไม่งั้น memory leak

ส่วน Python / Java / JavaScript น้องไม่ต้องสั่งเอง เพราะมี Garbage Collector (โปรแกรมที่ตามเก็บขยะใน memory ให้อัตโนมัติ ย่อว่า GC) คอยกวาด Heap ให้ ดีไงล่ะ แต่แลกมาด้วย overhead นิดหน่อย

Stack overflow มาจากไหน

Stack overflow มาจากไหน
Stack overflow มาจากไหน

จำได้ป่ะว่า function call เก็บของไว้ใน Stack ถ้าน้องเขียน recursion ลึกเกินไปแบบไม่มี base case (เงื่อนไขหยุดของ recursion ที่บอกว่า เมื่อไหร่ฉันควรเลิกเรียกตัวเอง) function ก็จะเรียกตัวเองไปเรื่อย ๆ ใส่กระดาษทับ Stack ไปเรื่อย ๆ จนกระดาษล้นโต๊ะ

1
2
3
4
def boom():
boom() # ทำซ้ำ ๆ จน Stack เต็ม
boom() # → RecursionError: maximum recursion depth exceeded

ปัง Stack overflow เว็บดัง ๆ ที่ตั้งชื่อนี้ก็เพราะเหตุการณ์นี้แหละ ฮา

Memory leak ก็คนละเรื่อง

Memory leak ก็คนละเรื่อง
Memory leak ก็คนละเรื่อง

ตรงข้ามกันคือ memory leak (การที่ของในหน่วยความจำไม่ถูกคืน คือใช้แล้วไม่ปล่อย) เกิดที่ Heap น้องสร้างของไว้บน Heap แล้วลืมลบเอง (ใน C/C++) หรือ GC ตามไม่ทัน (ในภาษาที่มี GC)

ผลคือ Heap โตขึ้นเรื่อย ๆ จน RAM หมด เครื่องช้า แล้วเด้ง นี่คือเหตุผลว่าทำไมบาง app เปิดทิ้งไว้นาน ๆ จะเริ่มกินแรมเป็น GB

สรุปแบบไม่ต้องจำ

  • Stack คือกองกระดาษ เร็ว มีระเบียบ ขนาดเล็ก ใช้กับ local variables และ function calls cleanup อัตโนมัติ
  • Heap คือห้องรก ๆ ใหญ่ ยืดหยุ่น ช้ากว่า ใช้กับ object ขนาดใหญ่ หรือของที่ share ข้าม function ต้องจัดการเองหรือพึ่ง GC
  • Stack overflow คือ recursion ลึกเกินจนกระดาษล้นโต๊ะ
  • Memory leak คือทิ้งของไว้บน Heap แล้วลืมเก็บคืน

ครั้งหน้าเขียน function ที่ใช้ array ใหญ่ ๆ ลองหยุดถามตัวเองก่อนว่า "นี่จะอยู่ Stack หรือ Heap" แค่นั้นน้องก็ดูเทพขึ้น 30% ละ ✌️