[Tutorial] สอนภาษา .Net :: ตอนที่ 07 หน่วยความจำประเภทต่างๆ Heap, Stack และ Registry

เงื่อนข้อตกลงในการใช้บทความนี้


การเข้าใจถึงประเภทของหน่วยความจำนั้นมีความสำคัญมากต่อการบริหารจัดการ Memory ในการเขียนโปรแกรมให้มีประสิทธิภาพ ซึ่งมือใหม่หลายคนนั้นยังไม่เข้าใจและอาจจะไม่ให้ความสำคัญมากนักเพราะเห็นว่าเป็นเรื่องไกลตัวแต่จริงๆ แล้วนั้นใช้บ่อยๆ ครับ

เพื่อให้อธิบายเข้าใจโดยง่ายผมจะขอยกตัวอย่างเปรียบเทียบกับการทำโจทย์คณิตศาสตร์นะครับ

1. Stack
คิดง่ายๆ ว่าเป็นกระดาษทำโจทย์เลขที่เราต้องเขียนค่าต่างๆ ลงไปในการทำโจทย์

2. Stack frame
เป็นช่วงบรรทัดที่เราจะใช้เขียนสูตรและค่าลงไปในการดาษทำโจทย์ เป็น subset ของ Stack

3. Heap
ว่าง่ายๆ มันคือกระดาษทดในการคิดเลข จำเป็นจะต้องมีการจองพื้นที่ที่จะใช้งานและแจ้งคืนพื้นที่ที่ไม่ใช้งานแล้วเพราะกระดาษทดใบนี้ใช้ร่วมกันหลายคน

4. Registry
เปรียบเทียบง่ายๆ คือพื้นที่ความจำที่เราใช้คิดเลขในใจครับ สามารถทำการคำนวณได้รวดเร็วแต่เก็บค่าได้ไม่มากนัก




ดังนี้ 1 โปรแกรมจะมี Stack 1 ตัวและมี Stack frame ย่อยๆ อีกมากมายซึ่ง 1 Stack frame ต่อ 1 method ครับ
Stack frame นั้นจะถูกทำลายทันทีหลังจากจบ method แล้ว ค่าต่างๆ ที่อยู่ในนี้เองก็จะถูกทำลายไปด้วยเช่นกัน
Heap นั้นไม่ขึ้นอยู่กับ method ใดๆ เพราะเป็นการดึงหน่วยความจำที่ว่างอยู่มาใช้งานชั่วคราว
ส่วน Registry นั้นในหลายภาษาไม่สามารถกำหนดใช้เองได้ยกเว้นบางภาษาเช่น C และ C++




Memory leak หรือก็คือการจองพื้นที่เอาไว้โดยไม่ได้ใช้งานอะไรซึ่งส่งผลทำให้ใช้ Ram มากเกินความจำเป็นโดยใช่เหตุซึ่งสาเหตุหลักๆ ของปัญหานี้นั้นได้แก่

1. ทำการจองพื้นที่ใน Heap แล้วลืมส่งคืน มักเกิดขึ้นในภาษาเช่นภาษา C ตลอดจนการเลือกที่จะสร้าง Dynamic memory เองแล้วจัดการไม่รัดกุมพอ

2. การสร้างค่าบน Stack frame โดยไม่คำนึงถึงการทำลาย Stack frame ซึ่งจุดนี้นั้นเป็นกันเยอะเนื่องจากไม่ค่อยมีใครใส่ใจตรงจุดและสามารถเกิดขึ้นได้ทุกภาษาตัวอย่างเช่น

Dim A = 5
Dim B = 10
Dim C = Power(A, B) '// AB
Dim D = Factorial(C)

Worker(A, B, C, D)

ในตัวอย่างนี้นั้นประกอบไปด้วยตัวแปร Integer 4 ตัว(A, B, C, D)แต่ละตัวมีขนาด 4 bytes ซึ่งรวมแล้ว 16 bytes + พื้นที่พักรับส่งค่าซึ่งจะใช้ค่าสูงสุดซึ่งก็คือ 4 จาก Worker method และค่าแต่ละตัวนั้นเป็น Integer เช่นกันจึงรวมเป็น 16 bytes
ดังนี้ Method นี้จะสร้าง Stack frame ขนาด 16 + 16 = 32 bytes

ซึ่งพื้นที่จำนวน 32 bytes นี้นั้นจะถูกตีตราว่าใช้งานอยู่จนกว่า Worker method จะทำงานเสร็จ หากเขียน Worker method โดยไม่คำนึงปล่อยให้ทำไปยืดยาวแล้วก็จะเกิดการสูญปล่าวไปเรื่อยๆ และยิ่งถ้ามีการเรียกใช้ Method นี้จาก Thread ต่างๆ ก็จะยิ่งทำให้เพิ่มการใช้ ram โดยไม่จำเป็นมากขึ้นเรื่อยๆ

ดังนี้ method ที่มีการเรียกใช้บ่อยและคงอยู่ยาวนานนั้นไม่ควรสร้างค่าอะไรลงไปเท่าที่จะทำได้ อย่าง main() เองนั้นก็ไม่ควรจะสร้างค่าอะไรมากเช่นกัน หรือพวก Recursive method ซึ่งสามารถบรรเทาได้ด้วยการให้ทำการแยกส่วนไปสร้าง method เล็กๆ แล้วเรียกใช้แทน

หมายเหตุ :: เหตุในข้อ 2 นี้สามารถแก้ไขได้ด้วยการ invoke method ด้วย jmp(Jump)/tail call แทนการ call ทั่วไป


หากบทความนี้ถูกใจ เป็นประโยชน์ ขอรบกวนผู้อ่านกด [+] ด้วยนะครับ ขอบคุณครับ พาพันขอบคุณ
แสดงความคิดเห็น
โปรดศึกษาและยอมรับนโยบายข้อมูลส่วนบุคคลก่อนเริ่มใช้งาน อ่านเพิ่มเติมได้ที่นี่