|
หลักการ ...
Memory Leak เป็นปัญหาที่เกิดขึ้นจากการจัดการทรัพยากรในโปรแกรมที่ไม่ถูกต้องหรือไม่สมบูรณ์ เกิดขึ้นเมื่อ:
- หน่วยความจำ (Memory) ถูกจัดสรร (Allocated) แต่ไม่ถูกคืนให้ระบบ (Deallocated) แม้จะไม่ใช้งานแล้ว
- ตัวจัดเก็บขยะ (Garbage Collector) ไม่สามารถคืนหน่วยความจำนั้นได้ เพราะยังมีการอ้างอิง (Reference) ค้างอยู่ในโปรแกรม
ตัวอย่าง:
การสร้างวัตถุ (Object) แต่ไม่ลบหรือปล่อยหน่วยความจำที่เกี่ยวข้อง
ผลกระทบ:
- หน่วยความจำที่ถูกใช้งานจะเพิ่มขึ้นเรื่อยๆ
- โปรแกรมทำงานช้าลงหรือขัดข้อง (Crash) เมื่อหน่วยความจำหมด
วิธีตรวจสอบ Memory Leak:
- ดูการ Dispose
- ใช้การ Breakpoint ใน Dispose เพื่อตรวจสอบว่า Resource ถูกปลดปล่อยอย่างเหมาะสม
- Task Manager ตรวจสอบการใช้หน่วยความจำของแอปพลิเคชันใน Task Manager
- Profiler Tools ใช้ Visual Studio Diagnostic Tools หรือ .NET Memory Profiler เพื่อตรวจหาการรั่วไหลของ Memory
การที่ VB.NET มี Me.Dispose() ให้ใช้งานอยู่แล้ว เป็นเพราะ Dispose เป็นส่วนหนึ่งของกลไก การจัดการทรัพยากร (Resource Management) ซึ่งถูกกำหนดไว้ใน IDisposable Interface. อย่างไรก็ตาม การที่เราเขียน Protected Overrides Sub Dispose ขึ้นมาเอง มีเหตุผลสำคัญดังนี้ ...
1. การจัดการทรัพยากรเพิ่มเติม (Custom Resource Management)
ค่าเริ่มต้นของ Dispose ใน Form จะทำลายเฉพาะทรัพยากรที่ถูกเพิ่มผ่านตัวควบคุม (Controls) หรือทรัพยากรที่ Windows Forms สร้างขึ้น เช่น Control Handle หรือ GDI+ Resources แต่ถ้าคุณสร้างทรัพยากร เฉพาะเจาะจง (เช่น Font, Stream, Bitmap) คุณต้องจัดการทรัพยากรเหล่านี้เอง
2. การปรับแต่งกระบวนการ Dispose
ในบางกรณี คุณอาจต้องปรับแต่งพฤติกรรม Dispose เช่น
- แสดงข้อความ Debug
- ปิดการเชื่อมต่อฐานข้อมูล
- เขียน Log หรือ ปิดทรัพยากรที่ไม่ได้จัดการ (Unmanaged Resources)
โค้ดตัวอย่างนี้จะเป็นการ Custom Font หรือการปรับฟอนต์ใหม่กับปุ่มคำสั่ง (คำอธิบายอยู่ใน Class CustomFont.vb) ซึ่งจะต้องทำการ Debugger เท่านั้น ถึงจะเห็นผลลัพธ์ได้ ...
คำอธิบายเพิ่มเติม:
Custom Control:
คลาส CustomButton สืบทอดจาก Button และเพิ่มการจัดการ Resource (Font)
Dispose Method:
เรา Override เมธอด Dispose เพื่อปลดปล่อย Resource (เช่น Font)
OnPaint Method:
ใช้ Font ในการวาดข้อความลงบนปุ่ม
Debug ตรวจสอบ:
ใช้ Debug.WriteLine เพื่อแสดงข้อความใน Immediate Window (กด Ctrl + G ก็จะโชว์หน้าจอนี้ขึ้นมา) เมื่อ Resource ถูก Dispose
ใน VB.NET, คำสั่ง Protected Overrides ถูกใช้เพื่อ เขียนทับ (Override) เมธอดหรือฟังก์ชันที่ถูกประกาศในคลาสฐาน (Base Class) โดยทำงานในคลาสที่สืบทอดมา (Derived Class).
คำอธิบายองค์ประกอบ
Protected:
- ระดับการเข้าถึง (Access Modifier) ที่กำหนดให้เมธอดหรือฟังก์ชันสามารถเข้าถึงได้เฉพาะในคลาสนั้นเองหรือในคลาสที่สืบทอดจากมัน
- ทำให้ไม่สามารถเรียกใช้งานโดยตรงจากภายนอกคลาสได้
Overrides:
- บอกคอมไพเลอร์ว่าเมธอดนี้จะ เขียนทับ (Override) เมธอดหรือฟังก์ชันที่มีการประกาศไว้ในคลาสฐาน (Base Class)
- ใช้ได้ก็ต่อเมื่อเมธอดในคลาสฐานมีการประกาศด้วย Overridable, MustOverride, หรือ Virtual (ในกรณีของ C#).
Dispose(disposing As Boolean):
- เป็นเมธอดใน .NET Framework ที่มักถูกใช้เพื่อจัดการกับ Unmanaged Resources (เช่น ไฟล์, การเชื่อมต่อฐานข้อมูล, หรือ Handle ของระบบ).
- คลาสที่สืบทอดมาจาก Component หรือ Control จะมีเมธอดนี้เพื่อให้สามารถกำหนดขั้นตอนการปล่อยทรัพยากรเพิ่มเติมได้
- Imports System.Diagnostics
- Imports System.Windows.Forms
- Public Class CustomButton
- '// คำสั่ง Inherits Button ระบุว่า CustomButton เป็นคลาสลูกของ Button (Inheritance)
- '// หมายความว่า CustomButton มีคุณสมบัติและพฤติกรรมของ Button ทั้งหมด และสามารถขยายหรือเปลี่ยนแปลงพฤติกรรมเหล่านั้นได้.
- Inherits Button
- '// ถ้าเราไม่ทำลาย CustomFont ด้วยตัวเอง จะเกิด Memory Leak
- '// เนื่องจากทรัพยากรของ Font ไม่ได้ถูกจัดการโดยตัวจัดเก็บขยะ (Garbage Collector)
- Private CustomFont As Font
- Public Sub New()
- '// สร้าง Font ใหม่
- CustomFont = New Font("Arial", 13, FontStyle.Bold)
- End Sub
- Protected Overrides Sub OnPaint(e As PaintEventArgs)
- MyBase.OnPaint(e)
- '// ใช้ Resource (Font) เพื่อวาดข้อความ
- e.Graphics.DrawString("Custom Button", CustomFont, Brushes.Black, 12, 5)
- End Sub
- '// แม้ว่า VB.NET จะมี Me.Dispose() อยู่แล้ว แต่การเขียน Protected Overrides Sub Dispose เองจะช่วยให้:
- '// - สามารถจัดการทรัพยากรเฉพาะที่คุณสร้างเองได้
- '// - ป้องกัน Memory Leak โดยการทำลายทรัพยากรที่ระบบจัดการไม่ได้
- '// - ปรับแต่งกระบวนการ Dispose เพื่อรองรับการทำงานพิเศษ
- '// - รองรับการสืบทอดคลาสที่ซับซ้อน
- '// การใช้ Dispose แบบกำหนดเองเหมาะสำหรับ กรณีที่โปรแกรมมีการใช้ทรัพยากรที่ต้องกำจัดด้วยตนเอง
- '// หรือมีการจัดการทรัพยากรที่ซับซ้อน
- Protected Overrides Sub Dispose(disposing As Boolean)
- If disposing Then
- '// ตรวจสอบและทำลาย Resource
- If CustomFont IsNot Nothing Then
- CustomFont.Dispose()
- CustomFont = Nothing
- '// กด Ctrl + G เพื่อดูผลลัพธ์จากหน้าจอ Immediate Window
- Debug.WriteLine("Custom Font ถูก Dispose แล้ว")
- End If
- End If
- '// เรียก Dispose ของคลาสฐาน
- MyBase.Dispose(disposing)
- End Sub
- End Class
คัดลอกไปที่คลิปบอร์ด
โค้ดหน้าจอฟอร์มหลัก ...
- Public Class frmMain
- Inherits Form
- Private Sub frmMain_FormClosed(sender As Object, e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
- '// กระโดดไปที่ Class CustomButton.vb
- Me.Dispose()
- Application.Exit()
- End Sub
- Private Sub frmMain_Load(sender As Object, e As System.EventArgs) Handles Me.Load
- ' ตั้งค่าฟอร์ม
- Me.Text = "Test Memory Leak"
- Me.Size = New Drawing.Size(360, 300)
- Me.StartPosition = FormStartPosition.CenterScreen
- '// สร้างปุ่ม CustomButton
- Dim btn As New CustomButton() With {
- .Text = "Click Me",
- .Size = New Drawing.Size(150, 90),
- .Location = New Drawing.Point(100, 100)
- }
- Me.Controls.Add(btn)
- End Sub
- End Class
คัดลอกไปที่คลิปบอร์ด ดาวน์โหลดโค้ดต้นฉบับ VB.NET (2010) ได้ที่นี่ ...
|
ขออภัย! โพสต์นี้มีไฟล์แนบหรือรูปภาพที่ไม่ได้รับอนุญาตให้คุณเข้าถึง
คุณจำเป็นต้อง ลงชื่อเข้าใช้ เพื่อดาวน์โหลดหรือดูไฟล์แนบนี้ คุณยังไม่มีบัญชีใช่ไหม? ลงทะเบียน
x
|