ชุมชนคนรักภาษาเบสิค - Visual Basic Community

 ลืมรหัสผ่าน
 ลงทะเบียน
ค้นหา
ดู: 133|ตอบกลับ: 0

[VB.NET] การบริหารจัดการ Memory Leak สำหรับ Custom Control หรือ User Control

[คัดลอกลิงก์]

320

กระทู้

512

โพสต์

6619

เครดิต

ผู้ดูแลระบบ

ทองก้อน ทับทิมกรอบ

Rank: 9Rank: 9Rank: 9

เครดิต
6619



หลักการ ...
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 จะมีเมธอดนี้เพื่อให้สามารถกำหนดขั้นตอนการปล่อยทรัพยากรเพิ่มเติมได้
  1. Imports System.Diagnostics
  2. Imports System.Windows.Forms

  3. Public Class CustomButton
  4.     '// คำสั่ง Inherits Button ระบุว่า CustomButton เป็นคลาสลูกของ Button (Inheritance)
  5.     '// หมายความว่า CustomButton มีคุณสมบัติและพฤติกรรมของ Button ทั้งหมด และสามารถขยายหรือเปลี่ยนแปลงพฤติกรรมเหล่านั้นได้.
  6.     Inherits Button

  7.     '// ถ้าเราไม่ทำลาย CustomFont ด้วยตัวเอง จะเกิด Memory Leak
  8.     '// เนื่องจากทรัพยากรของ Font ไม่ได้ถูกจัดการโดยตัวจัดเก็บขยะ (Garbage Collector)
  9.     Private CustomFont As Font

  10.     Public Sub New()
  11.         '// สร้าง Font ใหม่
  12.         CustomFont = New Font("Arial", 13, FontStyle.Bold)
  13.     End Sub

  14.     Protected Overrides Sub OnPaint(e As PaintEventArgs)
  15.         MyBase.OnPaint(e)

  16.         '// ใช้ Resource (Font) เพื่อวาดข้อความ
  17.         e.Graphics.DrawString("Custom Button", CustomFont, Brushes.Black, 12, 5)
  18.     End Sub

  19.     '// แม้ว่า VB.NET จะมี Me.Dispose() อยู่แล้ว แต่การเขียน Protected Overrides Sub Dispose เองจะช่วยให้:
  20.     '// - สามารถจัดการทรัพยากรเฉพาะที่คุณสร้างเองได้
  21.     '// - ป้องกัน Memory Leak โดยการทำลายทรัพยากรที่ระบบจัดการไม่ได้
  22.     '// - ปรับแต่งกระบวนการ Dispose เพื่อรองรับการทำงานพิเศษ
  23.     '// - รองรับการสืบทอดคลาสที่ซับซ้อน

  24.     '// การใช้ Dispose แบบกำหนดเองเหมาะสำหรับ กรณีที่โปรแกรมมีการใช้ทรัพยากรที่ต้องกำจัดด้วยตนเอง
  25.     '// หรือมีการจัดการทรัพยากรที่ซับซ้อน
  26.     Protected Overrides Sub Dispose(disposing As Boolean)
  27.         If disposing Then
  28.             '// ตรวจสอบและทำลาย Resource
  29.             If CustomFont IsNot Nothing Then
  30.                 CustomFont.Dispose()
  31.                 CustomFont = Nothing
  32.                 '// กด Ctrl + G เพื่อดูผลลัพธ์จากหน้าจอ Immediate Window
  33.                 Debug.WriteLine("Custom Font ถูก Dispose แล้ว")
  34.             End If
  35.         End If
  36.         '// เรียก Dispose ของคลาสฐาน
  37.         MyBase.Dispose(disposing)
  38.     End Sub
  39. End Class
คัดลอกไปที่คลิปบอร์ด

โค้ดหน้าจอฟอร์มหลัก ...
  1. Public Class frmMain
  2.     Inherits Form

  3.     Private Sub frmMain_FormClosed(sender As Object, e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
  4.         '// กระโดดไปที่ Class CustomButton.vb
  5.         Me.Dispose()
  6.         Application.Exit()
  7.     End Sub

  8.     Private Sub frmMain_Load(sender As Object, e As System.EventArgs) Handles Me.Load
  9.         ' ตั้งค่าฟอร์ม
  10.         Me.Text = "Test Memory Leak"
  11.         Me.Size = New Drawing.Size(360, 300)
  12.         Me.StartPosition = FormStartPosition.CenterScreen

  13.         '// สร้างปุ่ม CustomButton
  14.         Dim btn As New CustomButton() With {
  15.             .Text = "Click Me",
  16.             .Size = New Drawing.Size(150, 90),
  17.             .Location = New Drawing.Point(100, 100)
  18.         }
  19.         Me.Controls.Add(btn)
  20.     End Sub
  21. End Class
คัดลอกไปที่คลิปบอร์ด
ดาวน์โหลดโค้ดต้นฉบับ VB.NET (2010) ได้ที่นี่ ...

ขออภัย! โพสต์นี้มีไฟล์แนบหรือรูปภาพที่ไม่ได้รับอนุญาตให้คุณเข้าถึง

คุณจำเป็นต้อง ลงชื่อเข้าใช้ เพื่อดาวน์โหลดหรือดูไฟล์แนบนี้ คุณยังไม่มีบัญชีใช่ไหม? ลงทะเบียน

x
สิ่งที่ดีกว่าการให้ คือการให้แบบไม่มีที่สิ้นสุด
ขออภัย! คุณไม่ได้รับสิทธิ์ในการดำเนินการในส่วนนี้ กรุณาเลือกอย่างใดอย่างหนึ่ง ลงชื่อเข้าใช้ | ลงทะเบียน

รายละเอียดเครดิต

ข้อความล้วน|อุปกรณ์พกพา|ประวัติการแบน|G2GNet.com  

GMT+7, 2024-12-13 01:09 , Processed in 0.172998 second(s), 4 queries , File On.

Powered by Discuz! X3.4, Rev.62

Copyright © 2001-2020 Tencent Cloud.

ตอบกระทู้ ขึ้นไปด้านบน ไปที่หน้ารายการกระทู้