Automatic Memory Management

Automatic memory management ถือเป็นอีกบริการหนึ่งของ Common Language Runtime (CLR) ซึ่งจะให้บริการระหว่าง Execution  

Garbage collector (GC) ใน CLR คือผู้ทำหน้าที่จัดสรร (allocation) และการคืน (Release) หน่วยความจำให้กับ Application ในมุมของ ผู้พัฒนานั้นก็หมายความว่าเราไม่ต้องเขียน Code เพื่อจัดการเรื่อง Memory เอง ในระหว่างการพัฒนา Application อีกต่อไป   นั่นก็หมายความว่า Automatic memory management ทำให้เรา เป็นการกำจัดปัญหาที่เกิดขึ้นซ้ำซากในเรื่องการจัดการ Memory  เช่นการลืมคืน Memory หลังจากที่ใช้ในการสร้าง Object และใช้งานเสร็จแล้ว ซึ่งเป็นที่มาของ Memory leak ที่เรารู้จักกันดี ในบทความนี้จะอธิบายการทำงานของ Garbage Collector ในการจัดสรร(Allocation) และการคืน (Release) Memory ให้กับ Application ว่าทำงานอย่างไร

Allocation Memory

เมื่อเราเริ่มการประมวลผล ครั้งใหม่  CLR จะทำการจอง(Reserve) พื้นที่ต่อเนื่องในหน่วยความจำให้กับการประมวลผล  พื้นที่ดังกล่าวเรียกว่า Managed heap.

Managed heap นี้จะเก็บ Pointer ชี้ไปยัง ตำแหน่งที่จะจัดสรรให้กับ Object อันถัดไปใน Heap ซึ่ง Pointer นี้จะชี้ไปที่ Base Address ของ Manage Heap. เมื่อ Application สร้างตัวแปรชนิดที่เป็น Reference type ตัวแรก  หน่วยความจำจะถูกจองให้กับตัวแปรตัวนั้นเริ่มที่ Base Address ใน Manage heap แล้วทำการชี้ Point Address ไว้ที่ตำแหน่งถัดจากตัวแปรนี้ หรือ Object นี้ และเมื่อ Application สร้าง Object ตัวต่อไป Garbage collector  จะจองพื้นที่ใน Managed heap ต่อจาก Object แรกตรงตำแหน่งที่ Pointer Address ชี้อยู่ แล้ว ขยับ Pointer Address ไปยังตำแหน่งถัดไป ทำอย่างนี้ไปเรื่อย ๆ ตราบใดที่ยังมีพื้นที่เหลืออยู่

การจัดสรร Memory ใน Manage Heap นั้นอาจกล่าวได้ว่า เร็วกว่าการจัดสรรใน Unmanaged memory เพราะว่า การทำใน CLR นั้นเป็นการเพิ่มหรือต่อท้ายพื้นที่ใน Memory และมี Pointer Address ชี้อยู่ อาจกล่าวได้ว่ามีความเร็วเท่ากับการ จัดสรร Memory ใน Stack เลยก็ว่าได้ นอกจากนี้การเข้าถึง Object ที่สร้างขึ้นนั้นก็รวดเร็วเนื่องจากการจัดสรร Memory นั้นเป็นการทำแบบต่อเนื่องกันดังที่ได้กล่าวไปแล้ว มีลักษณะตามภาพด้านล่าง

Releasing Memory 

กลไกการ optimizing ของ Garbage collector (GC) จะหาช่วงเวลาที่เหมาะสมเพื่อรวบรวมรายการของ การ Allocations ( ขอใช้คำทับศัพท์นะครับความหมายจะได้ไม่คลาดเคลื่อน ) ตามที่ถูกสร้างขึ้น 

เมื่อ GC รวบรวมรายการได้ ก็จะตรวจสอบและ คืน Memory ที่ item ที่ไม่ได้ถูกใช้งานโดยตรวจสอบกับ Root ในแต่ละ Application จะมีกลุ่มของ Root ที่อ้างอิงไปยัง Object ที่สร้างขึ้นและอยู่ ใน Managed heap หรือ ถ้ายังไม่ได้ถูกสร้างขึ้นจะมีค่าเป็น null  ใน Application root หนึ่ง ๆ นั้นจะมี static field , local variable และ parameters บน stack ของ thread รวมถึง CPU Register   GC Collector สามารถเข้าถึงไปยังรายการของ Active Roots ที่ CLR ดูแลอยู่ และโดยการใช้รายการนี้ สามารถที่จะตรวจสอบ Application root และรายการ object ที่ถูกสร้างขึ้นในระหว่างการประมวลผล ได้ ถ้า Object ใดที่ไม่ได้อยู่ในรายการ ที่เข้าถึงผ่านทาง Application root ได้ GC จะพิจารณาได้ว่า object นั้นไม่ได้ถูกอ้างอิงใช้งานแล้ว และจะทำการคืน Memory ของ ตำแหน่ง object นั้นกลับไปให้เป็น ที่ว่าง  

ในขณะการทำ Collection ของ GC มันก็จะทำการตรวจสอบ Managed heap และมองหาพื้นที่ของ address space ที่ถูกจองและไม่ได้ถูกใช้แล้ว หรือเรียกว่าถูกครอบครองด้วย Object ที่ไม่สามารถเข้าถึงได้ เนื่องจากไม่ได้มีการอ้างอิงใช้งานแล้ว  เมื่อพบก็จะทำการที่เรียกว่า  Compact  Object ที่เข้าถึงได้(reachable objects) ใน memory โดยการ ขยับ ลงไปทับเพื่อให้พื้นที่ว่างของ Managed heap เป็นพื้นที่ที่ต่อเนื่องกัน เป็นผืนเดียวกัน ไม่ให้เป็น พื้นที่ ย่อย ๆ เล็ก  เมื่อ Reachable Object ถูก compact แล้ว GC ก็จะทำการปรับตำแหน่งของ pointer ให้ถูกต้องกับตำแหน่งใหม่และ Application root สามารถเข้าถึง object ได้ถูกต้อง  

การทำ Memory compact นั้นจะทำก็ต่อเมื่อ GC Collection ตรวจพบว่ามี Unreachable objects จำนวนมากพอ หรือ เข้าขั้นวิกฤติแล้วเท่านั้น ถ้า objects ทั้งหมด ใน Managed heap ยังคงอยู่ในสภาพคล่อง ก็ยังคงไม่จำเป็นต้องทำ Memory Compact.

Categories: C# .NET

เรื่องของ Managed Code

เมื่อเราทำงานกับ .NET Framework เราจะได้เจอกับคำว่า “Managed code”  ในเอกสารนี้จะอธิบายความหมายของคำนี้รวมถึงข้อมูลต่าง ๆ ที่เกี่ยวข้องที่ต้องรู้

เพื่อให้ง่ายต่อความเข้าใจ ว่า Managed code คืออะไร ให้คำจำกัดความง่าย คือ Code ที่ทำงานภายใต้การจัดการของ Runtime ซึ่งการหมายถึง Common Language Runtime หรือ CLR  ไม่ว่าจะเป็น .NET Framework  .NET Core หรือ Mono ก็ตาม   CLR มีหน้าที่ในการ compiling  Managed code ให้เป็น Machine Code และทำการ และสั่งให้ทำงาน ซึ่งใน CLR นั้นมีบริการต่าง ๆ ที่สำคัญให้ เช่น Automatic Memory management , security boundaries, type safety เป็นต้น

ในทางตรงกันข้าม ในวิถีของการทำงาน C/C++  ในที่นี้เราเรียกว่า Unmanaged code ซึ่งในโลกของ Unmanaged code นั้น Operating System มีหน้าที่ load และ run โปรแกรม นอกจากนี้โปรแกรมเมอร์จะต้องจัดการเอง เช่น เรื่องการใช้การจอง Memories จะต้องจองและคืนเอง เป็นต้น 

สำหรับ Managed Code นั้นเขียนขึ้นจากภาษาระดับสูง (high-level language ) ที่สามารถประมวลผลบน .NET ได้ เช่น C# , Visual Basic, F# และอื่น ๆ เมื่อเราทำการ Compile Code ที่เขียนขึ้นจากภาษาเหล่านี้ด้วย Complier ของ Managed Code เราจะยังไม่ได้ Machine code เลย สิ่งที่ได้เราจะเรียกว่า Intermediate Language Code ซึ่งจะต้องถูกแปลงเป็น Machine Code ด้วย CLR อีกครั้งหนึ่ง แต่ C++ นั้นเป็นภาษาหนึ่งที่ถูกยกเว้นจากข้อกำหนดดังกล่าวข้างต้น เนื่องจากมันสามารถที่จะ Compile ออก มาเป็น Machine code หรือ Unmanage binaries และประมวลผลบน Windows ได้เลย (ไม่ต้องทำงานบน CLR) ตามภาพ

ภาพจาก https://stackoverflow.com

Categories: C# .NET

Marshaling with C# แนะนำเรื่อง Marshaling

Marshaling คือกระบวนการในการสร้างทางเชื่อมต่อระหว่าง Manage Code และ Unmanaged code ก็คือการย้ายข้อมูลจากสภาพแวดล้อมแบบ managed ไปยัง unmanaged หรือในทางกลับกัน ซึ่งนี้ก็เป็นส่วนหนึ่งของ Core Services ของ CLR (Common Language Runtime) ด้วยเหตุที่ว่า โดยมากแล้วชนิดของข้อมูล (Types) ในสภาวะแวดล้อมแบบ Unmanaged นั้นไม่มีใน สภาวะแวดล้อมแบบManaged จึงจำเป็นจะต้องสร้าง Function ในการแปลงไปมาระหว่าง Managed Type และ Unmanaged Type ซึ่งนี่ก็คือการทำงานของกระบวนการ Marshaling.
เพื่อเป็นการ ทำความเข้าใจอีกครั้ง เราเรียก .NET Code ว่าเป็น Managed ก็เพราะว่ามันอยู่ภายใต้การควบคุมของ CLR ฉะนั้น Code อื่น ๆ นอกเหนือจากนี้เราเรียกว่า เป็น Unmanaged

Why Marshaling? ทำไมต้องมีกระบวนการนี่ด้วย
เป็นที่ทราบกันในหมู่นักพัฒนาโปรแกรมแล้วว่า ความเข้ากันได้ระหว่าง Managed และ Unmanaged นั้นไม่มี หรือจะกล่าวอีกอย่างหนึ่งได้ว่า .NET ไม่มีชนิดข้อมูลดังตัวอย่างนี้ HRESULT DWORD และ HANDLE ซึ่งมีอยู่ใน Unmanaged Code. ซึ่งก็ทำให้เราต้องหาแบบข้อมูลแทนหรือสร้างขึ้นมาเองเพื่อใช้งาน การกระทำนี้ก็คือการ Marshaling
ตัวอย่าง เช่น DWORD ของ Unmanaged code มันคือ unsigned 32-bit integer ซึ่งเราสามารถ marshal ด้วย System.UInt32 ใน .NET ดังนั้น System.UInt32 ก็เป็นแบบข้อมูลแทน DWORD ของ Unmanaged . หรือ ตัวอย่างอื่น ๆ เช่นในกรณีที่ชนิดข้อมูลเป็นแบบ Compound Types เช่น Structure , union ซึ่งไม่มีแบบข้อมูลรองรับใน สภาวะแวดล้อมของ Managed ดังนั้นจึงต้องมีการสร้างขึ้นใช้เอง(structures/classes) เพื่อใช้รองรับชนิดข้อมูล ของ Unmanaged types ที่เราต้องการใช้

 

Categories: C# .NET

Hello World… !

หวัดดีกับ blog ว่างๆ นานมากแล้วที่ไม่ได้มีเพิ่มเติมเนื้อหา วันเวลาผ่านไปรวดเร็วหลายๆ อย่างก็ผ่านไป จนวันนี้ Visual Stuidio 2019 แล้ว  ช่วงนี้เป็นช่วง X-mas ของปี 2019 ประสบการณ์ที่ผ่านไปหลายปีในเรื่องโปรแกรมมิ่ง ก็ขาดตอนไปมีสิ่งที่ตื่นเต้นน่าสนใจเขามาแทนที่ หลายปีมานี่ผมได้มีโอกาสงานอยู่ในโครงการเกี่ยวกับอากาศยานไร้คนขับของสถาบันที่ผมทำงานอยู่ เริ่มจากความชอบในการเล่นเครื่องบินบังคับ หรือพูดให้โก้เก้ ตามฝรั่ง ก็ เรียกว่า RC-Model ความหลงไหลพาผมเข้าไปสู่นักบิน UAV อืมฟังแล้วประหลาดเมื่อหลายปีก่อนไม่มีใครเขารู้จักกันหรอก ครับ จนเมื่อ 2-3 ปีมานี่ ส่วนที่ทำออกมาเป็นการค้า พี่ผู้คนมากมายนำไปใช้ในงานแล้วก็พากันเรียกมันว่า Drone คำนี้ มายังไงผมก็ไม่ทราบได้ แต่พอเรียกคำนี้ก็เป็นอันรู้กัน แต่ผู้คนก็มักจะรู้จักกันในรูปร่างหน้าตาแบบด้านล่างนี้

Unknown       Phantom 4 Advanced drone de cuatro helices 4k

ครับแบบนี้เราเรียกันว่าโดรน หรือ Drone ก็แล้วแต่ ในมุมมองของนักพัฒนา UAV อย่างพวกเราๆ ก็เรียกมันว่า มัลติโรเตอร์หรือแบบเจาะจงลงไปเลยก็คือ Quad Rotor คือมันมีใบพัดที่หมุนได้ถึง 4 ใบครับ เวลามันจะขึ้นมันก็หมุน พอใบพัดหมุนได้ความเร็วรอบระดับหนึ่งมันก็ลอยขึ้นฟ้า คนบังคับได้ ซ้าย ขวา หน้า หลัง ติดกล้องความระเอียดสูงไปด้วย ส่งภาพลงมาใสกระจ่างชัดเจน ก็เอามาทำประโยชน์กันไปตามแต่จะใช้กัน เล่าไปเล่ามามันก็เลอะเทอะมาถึงนี่ได้อย่างไรก็ไม่รู้  แต่ที่ผมทำมันไม่ใช่แบบนี้หรอกครับวันหลังจะเล่าให้ฟัง ไม่รู้จะมีใครอ่านหรือป่าว ฮะฮะ พูดไปเรื่อยเปื่อย แต่เราเป็นคนเขียนโปรแกรม หรือเขามักจะเรียกกันว่าโปรแกรมเมอร์ มีคำกล่าวว่า  ” After three days without programming , life becomes meaningless ” จริงแท้แน่นอน ครับในมุมหนึ่งของพวกเราเป็นโลกส่วนตัวที่ยากจะเข้าใจ เพราะไม่รู้จะบอกอย่างไรให้ใครเข้าใจ ฮิ ฮิ งง งง

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

เอาไว้ติดตามกันละกันนะครับมีเรื่องอะไรอีกมากมายอยากเขียนให้ คนที่อาจหลงทางมาอ่าน blog กะผม

11705361_10204014564630818_4046123318596827966_n

 

Categories: C# .NET

ว่าด้วยเรื่อง Memory Static , Stack , Heap ในมุมของโปรแกรมเมอร์

การเป็นโปรแกรมเมอร์ที่ดี นั้นจำเป็นจะต้องเข้าใจ “What goes where” หรือ อะไรไปทางไหน ครับสิ่งที่จะกล่าวนั้น อยู่บนพื้นฐานการใช้งาน Memory ของ C programming  เพื่อให้การเขียนโปรแกรมเป็นไปได้อย่างมีประสิทธิภาพสูงสุด ในบทความนี้ก็เลยจะพูดถึง Memory ที่ถูกใช้งานระหว่างการเขียนโปรแกรม ครับ

( ในบทความนี้ อยู่บนพื้นฐานของ C programming นะครับ )

ใน C programming นั้นจะมีการใช้ Memory อยู่ 3 ชนิดคือ

  • static : เก็บค่าตัวแปรชนิด global  ซึ่งจะอยุ่ฐาวรจนกว่าจะจบโปรแกรม
  • stack : เก็บค่าตัวแปรที่เป็น local หรือตัวแปรที่ประกาศใน function
  • heap : dynamic storage (เป็นพื้นที่ความจำขนาดใหญ่การแบ่งใช้ไม่เป็นลำดับ) 


picture form https://craftofcoding.wordpress.com

STATIC Memory

จากที่ได้กล่าวไว้ตั้งแต่เบื้องต้นนะครับ  static memory จะอยู่ถาวรจนกว่าจะจบโปรแกรม ซึ่งโดยมากจะใช้เก็บค่าตัวแปร global หรือ ตัวแปรที่ประกาศนำด้วย static เช่น

int val ;

ในหลายๆ ระบบ ตัวแปรนี้จะใช้พื้นที่ในหน่วยความจำ จำนวน 4 bytes  หน่วยความจำดังกล่าวนี้อาจมาได้จาก 2 ที่  ถ้า ตัวแปรนี้ประกาศ นอก function ก็จะพิจารณาว่าเป็น global  หมายถึง สามารถเข้าถึงจากที่ไหนก็ได้ในโปรแกรม  และ ตัวแปร global  เป็น static ซึ่งมีชุดเดียวตลอดในโปรแกรม

ตัวแปรใน function เป็น local  ซึ่งจะใช้พื้นที่ของ stack แต่ก็สามารถที่จะบังคับให้เป็น ตัวแปร static ได้โดยการนำหน้าด้วย static cluse. เช่นตัวแปรตัวเดียวกันหากประกาศใน function แต่ถ้านำหน้าด้วย static ก็จะทำให้ถูก ใช้ในพื้นที่ ใน static memory ได้

static int val;

STACK MEMORY

หน่วยความจำstack ใช้เก็บค่าตัวแปรใช้ภายใน function (รวมถึงใน main() function ด้วย )   หน่วยความจำ stack มีโครงสร้างเป็นแบบ LIFO “Last-In-First-Out” ทุกครั้งที่มีการประกาศตัวแปรใน function 9 ตัวแปรจะถูก Push ลงบนstack และเมื่อ function นั้นจบการทำงานตัวแปรทั้งหมด ที่อยู่ใน function จะถูกลบออกและหน่วยความจำนั้นก็จะว่างลง

Stack เป็นพื้นที่ของ หน่วยความจำที่พิเศษ ถูกจัดการด้วย CPU ดังนั้นเราไม่จำเป็นจะต้องทำการ จอง (allocate) หรือ คืน (deallocate) พื้นที่หน่วยความจำ

Stack ถูกแบ่งออกเป็น frame ต่อเนื่องกัน ในขณะที่ function ถูกเรียกนั้น stack frame ใหม่ จะถูก จองใช้งาน

ข้อจำกัดของขนาดของหน่วยความจำ stack นั้นแตกต่างกันไปตาม OS (เช่น OSX มีขนาด stack เท่ากับ  8MB) ถ้าโปรแกรม พยายามใช้ stack มากเกินไป จะเกิด stack overflow ซึ่งก็หมายถึง หน่วยความจำ stack ถูกจองใช้หมด  นอกจากนี้การ เขียน recursion ที่ไม่ถูกต้องก็เป็นอีกสาเหตุที่ทำให้ เกิด stack overflow ด้วย

บทสรุปของ stack

  • หน่วยความจำ stack ถูกจัดการโดย CPU ไม่สามารถเข้าไปแก้ไขได้
  • ตัวแปรถูกจองและคืนพื้นที่อัตโนมัติ
  • พื้นที่หน่วยความจำ stack มีจำกัด – ส่วนมากจะถูกกำหนด upper bound
  • stack ขยายและลดขนาดในขณะที่สร้างตัวแปรและลบตัวแปรไป
  • ตัวแปร stack จะปรากฏก็ต่อเมื่อ function ที่สร้างมันยังคงอยู่

HEAP Memory

เป็นพื้นที่สำหรับการเรียกใช้แบบ dynamic ตรงข้ามกับการใช้งานแบบ stack  หรือเรียกอีกอย่างหนึ่งว่า “free store “ ผู้ใช้เป็นผู้ใช้ จองใช้งานเองไม่ได้ใช้งานแบบ อัตโนมัติ โดย function เช่น malloc() และคืน เช่น free()   การพยายาม free() หน่วยความจำขณะถูกใช้งานอยู่ทำให้การ คืน memory ล้มเหลวและทำให้เกิด memory leak  ทำให้ process อื่น ไม่สามารถจิงใช้งานได้

เรื่อง ขนาดของ HEAP  นั้นค่อนข้างจะไม่จำกัด ซึ่งขึ้นอยู่กับ physical memory และตัวแปรที่ สร้างใน heap สามารถเข้าถึงได้จากทุกที่ในโปรแกรม และ heap memory นี่เองที่เราจะต้องใช้ pointers

บทสรุปของ HEAP

  • หน่วยความจำ HEAP จัดการโดยผู้ใช้ไม่มีขอบเขตในการเข้าถึง
  • ใน C ตัวแปรถูกจองและคืนโดยใช้ function เช่น malloc() และ free()
  • HEAP เป็นส่วนของหน่วยความจำขนาดใหญ่และถูกจำกัดโดย physical memory
  • HEAP เข้าถึงด้วยการใช้ pointer

ตัวอย่าง ของการใช้ memory

ลองพิจารณา code ต่อไปนี้ครับ

picture form https://craftofcoding.wordpress.com

ตัวแปร x เป็น static เพราะว่า เป็นการประกาศแบบ global

ตัวแปร y และ str เป็น stack ซึ่งจะถูกคืนพื้นที่เมื่อโปรแกรมจบ

function malloc() นั้นใช้สำหรับการจองพื้นที่ 100 ช่อง ของ หน่วยความจำ heap แต่ละช่องมีขนาดตาม size ของ char  ให้กับตัวแปร str

function free() สำหรับคืนพื้นที่ ที่ ชี้โดย str

picture form https://craftofcoding.wordpress.com

เป็นไงกันบ้างครับ ทั้งหมดนี้เป็น แนวคิดการใช้งาน พื้นที่หน่วยความจำของตัวแปรแต่ละประเภท สหรับโปรแกรมเมอร์ควรจะต้องเข้าใจกันสักนิสหนึ่ง ผมมั่นใจว่า เราเคยเจอ stack overflow และ memory leak กันเป็นประจำอยู่แล้วในงานการพัฒนาโปรแกรม เกร็ดเล็กเกร็กน้อยช่วยเราให้สามารถหาข้อมูลแก้ไขต่อไปได้ ครับ

Categories: C++