Set obj = Nothing เพื่อ ...
กระทู้เก่าบอร์ด อ.Yeadram

 1,953   6
URL.หัวข้อ / URL
Set obj = Nothing เพื่อ ...

สวัสดีครับ ... หลายคนอาจยังสงสัยว่าการกำหนดให้ set obj = Nothing นั้น มันคืออะไร ถ้าไม่ทำแล้วมันจะเกิดอะไรขึ้นกับระบบ ตอนนี้พอดีว่างๆก็เลยมาขอแจมหน่อย ...

ถ้า obj เป็นตัวแปรอ๊อปเจค นั่นคือมีการกำหนดด้วยคำสั่ง Dim obj as Object หรือ Dim obj as <คลาสอะไรสักอย่าง> เช่น Dim obj as DAO.Recordset หรือ Dim obj as Access.Application เป็นต้น obj จะเป็นตัวแปรที่เพียงแค่ชี้ไปยังตัวอ๊อปเจคตัวจริงที่จะเกิดขึ้นในหน่วยความจำนั่นเอง หรือที่รู้จักกันในนามว่ามันเป็นตัวชี้ (pointer) ซึ่งกินเนื้อที่เพียง 32 bits หรือ 4 bytes เท่านั้น เมื่อเริ่มคำสั่ง Dim ตัวแปร obj นี้จะไม่ได้ชี้ไปยังอ๊อปเจคตัวจริงใดๆเลย ถ้าทดสอบด้วยประโยค If obj Is Nothing then ก็จะให้ค่า True จนกว่าจะกำหนด obj ให้มีค่าด้วยคำสั่ง set obj = .... แล้วเท่านั้น obj จึงจะชี้ไปยังอ๊อปเจคตัวจริงที่ถูกสร้างขึ้นในหน่วยความจำและทำให้เราอ้างอิงคุณสมบัติและค่าต่างๆของอ๊อปเจคนั้นๆผ่านตัวแปร obj ได้นั่นเอง ที่นี้เมื่อเราไม่ใช้ออปเจคนั้นต่อไปแล้ว เราก็ควรตัดไม่ให้ตัวแปร obj ชี้ไปยังอ๊อปเจคตัวจริงอีกต่อไปด้วยคำสั่ง set obj = Nothing จุดนี้เองที่มีปัญหาเพราะโดยที่เข้าใจกันว่าตัวแปรต่างๆที่อยู่ใน procedure นั้นจะถูกเคลียทิ้งเองโดยระบบอย่างอัตโนมัติอยู่แล้วเมื่อออกจาก procedure ที่สร้างตัวแปรนั้น แต่ผู้รู้หลายคนบอกว่าสำหรับตัวแปรอ๊อปเจคนั้น ระบบอาจไม่สามารถเคลียทิ้งได้ 100 เปอร์เซนต์ ดังนั้นเมื่อทำงานไปหลายๆครั้ง ทรัพยากรจะลดลงไปเรื่อยๆๆๆ ยิ่งถ้าเป็นการทำงานในลูป อาจทำให้เกิด Out of memory ในที่สุด เราจึงต้องสั่งเคลียเองด้วยคำสั่ง set obj = Nothing

จุดต่อมาที่ต้องทำความเข้าใจก็คือ ตัวอ๊อปเจคจริงๆที่ตัวแปร obj ชี้ไปนั้น มันไม่ได้ถูกเคลียด้วยคำสั่ง set obj = Nothing หรอกนะครับ ตัวอ๊อปเจคตัวจริงจะปลดปล่อยทรัพยากรต่างๆหรือไม่นั้น ก็ขึ้นกับคนเขียนตัวอ๊อปเจค (เขียนคลาส) นั้นๆว่าจะให้ปลดปล่อยทรัพยากรเมื่อไหร่ เช่น อาจปลดปล่อยเมื่อเจอเมธอด .Close เหมือนอย่าง Recordset อ๊อปเจค หรือ .Quit สำหรับ Access อ๊อปเจค ดังนั้นถ้าเราไม่ทำตามขั้นตอนที่ถูกต้องเพื่อจบการใช้งานอ๊อปเจคนั้น เช่นไม่สั่ง .Close แต่ทำเฉพาะ set obj = Nothing แล้ว สิ่งที่เกิดขึ้นก็คือ ระบบจะมีอ๊อปเจคตัวจริงๆนั้นค้างอยู่ในระบบโดยที่เราไม่สามารถไปอ้างอิงหรือควบคุมอ๊อปเจคตัวนั้นได้อีกเลย เปรียบเหมือนกับ "ผีเร่ร่อนไร้ร่างสิ่งสู่" แต่บางทีเราก็ต้องการทำให้มันเป็นเช่นนั้น แต่ทั้งนี้ทั้งนั้นเราจะต้องแน่ใจว่าจะมีทางควบคุมอ๊อปเจค "ผีเร่ร่อน" ได้ต่อไป เช่น กรณีถ้าเราต้องการเปิด Excel Sheet ขึ้นมาแล้วแปะค่าต่างๆลงในนั้น หลังจากนั้นเราก็ออกจาก procedure แล้วก็ปล่อยให้ Excel แสดงชีทให้ผู้ใช้ดูต่อไป หรือเราเรียกโปรแกรม Access ตัวอื่นมาทำงานต่อไปและโปรแกรมนั้นจะปิดตัว Access ไปในท้ายที่สุดเอง สำหรับ ตย.ของการเปิด Excel จะมีโครงสร้างโปรแกรมเป็นดังนี้

Private Sub OpenExcel( )
     Dim xlApp As Object ' กำหนดตัวแปรอ๊อปเจค

     Set xlApp = CreateObject("Excel.Application") ' สร้าง Excel อ๊อปเจค แล้วเชื่อมเข้ากับตัวแปรอ๊อปเจคที่สร้างขึ้น
     xlApp.Workbooks.Add ' สร้าง WorkBook
     xlApp.ActiveSheet.Cells(1, 1) = "Hello World"
     xlApp.Visible = True ' แสดงให้เห็น Excel
     xlApp.WindowState = xlMaximized ' ขยาย Excel ให้เต็มจอภาพ
     xlApp.ActiveWindow.WindowState = xlMaximized ' ขยายชีทให้เต็มหน้าต่างของ Excel
     Set xlApp = Nothing ' ตัดตัวแปรออกจากอ๊อปเจค
End Sub

สรุปสุดท้ายคือ ตัวแปรอ๊อปเจคและอ๊อปเจคตั?จริงนั้นแยกจากกัน และการเลิกใช้ตัวแปรอ๊อปเจคไม่ได้หมายความว่าอ๊อปเจคตัวจริงจะหายไปจากระบบ อ๊อปเจคบางตัวที่ค้างในระบบ สามารถกำจัดได้จากการสั่ง End Task ภายใน Task Manager แต่ต้องเป็นอ๊อปเจคที่เป็นโปรเซสแยกออกมาเฉพาะตัว

สุดท้ายหวังว่าคงจะเป็นประโยชน์เล็กๆน้อยๆนะครับ

6 Reply in this Topic. Dispaly 1 pages and you are on page number 1

1 @R00070
ขอบคุณครับอาจารย์
2 @R00072
ขอบคุณครับ อยากให้อาจารย์มีเวลาว่างอีกจัง
3 @R00127
ขอบคุณมากครับอย่างนี้ที่อยากได้เลย...
เออแล้ว dim กับ ไม่dim หละครับจะต่างไหม?
4 @R00129
ขอบคุณมากสำหรับความรู้ครับ อ.
5 @R00130
ที่ถามว่า Dim กับไม่ Dim จะต่างกันไหม ? คือยังไงก็ต้อง Dim อยู่แล้วนะครับ เพราะเป็นการสร้างตัวแปร เพียงแต่มีการ Dim ให้เป็นตัวแปรประเภท Object กับเป็นประเภทของคลาสนั้นๆไปเลย เช่น Dim xlApp as object เทียบกับ Dim xlApp as ครับ แบบแรกนั้น ตัวแปรจะยังไม่มีข้อมูลเฉพาะสำหรับคลาสนั้นๆ คลาสจะถูกกำหนดให้ตัวแปรอีกครั้งเมื่อโปรแกรมกำลังทำงานด้วยคำสั่งเช่น set xlApp = CreateObject("ชื่อคลาส") การที่ได้คลาสมาภายหลังนี้ ทำให้มีชื่อเรียกการกำหนดตัวแปรในแบบแรกว่า Late Binding (ผูกมัด(ประเภท)เข้าไปทีหลัง) ส่วนการสั่ง Dim xlApp as นั้นจะได้ชื่อเรียกว่า Early Binding (ผูกมัด(ประเภท)เข้าไปก่อน) ครับ

ส่วนข้อดีของแต่ละอย่างคือ Late Binding ก็ทำให้โค้ดที่คอมไพล์แล้วไม่ใหญ่ เพราะยังไม่มีข้อมูลเฉพาะของคลาสนั้นๆ และระหว่างรันโปรแกรม ตัวแปรประเภทนี้จะผูกเข้ากับคลาสใดๆก็ได้

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

"... แต่ทำเฉพาะ set obj = Nothing แล้ว สิ่งที่เกิดขึ้นก็คือ ระบบจะมีอ๊อปเจคตัวจริงๆนั้นค้างอยู่ในระบบ..."

ที่ถูกต้องกว่านั้นคือ ต้องดูว่าเป็นอ๊อปเจ็คอะไร ถ้าเป็น COM อ๊อปเจคแล้ว มีความเป็นไปได้ที่จะทำให้เกิดค้างไว้อย่างที่ว่า เพราะ COM จะเป็นตัวรับหน้าที่ในการจัดการต่อไปแม้ว่าจะไม่มีตัวแปรอ๊อปเจ็คอ้างถึงมันแล้วก็ตาม แต่ถ้าเป็นอ๊อปเจ็คภายในระบบ Access เอง เช่น ฟอร์ม, รายงาน, คิวรี่, เรคอร์ดเซ็ท ฯ อ๊อปเจ็คจะถูกทำลายทิ้งไปอย่างอัตโนมัติเมื่อไม่มีตัวแปรอ๊อปเจ็คใดมาอ้างอิงถึงมันอีกต่อไป ดังนั้นการทำแค่ set obj = nothing ที่ดูเหมือนจะน่าเพียงพอแล้ว หรือแม้แต่เราไม่กำหนด = nothing แต่ถ้าโปรแกรมเราออกมานอกขอบเขต (scope) ของตัวแปรนั้นๆ อ๊อปเจ็คที่ถูกอ้างอิงไปก็ถูกทำลายทิ้งไปได้เช่นกัน   อย่างไรก็ตาม การไม่กำหนด = nothing แล้วโปรแกรมออกจากขอบเขตของตัวแปรอ๊อปเจ็คนั้นไปเลย ก็เป็นบักใน Access (ไม่แน่ใจว่าเป็นบักใน VB ด้วยหรือไม่) เวอร์ชั่นเก่าๆมาแล้ว เพราะอ๊อปเจ็คจะไม่ถูกทำลายทิ้งไป หน่วยความจำก็จะหดหายไปเรื่อยๆ แต่ผู้รู้ฝรั่งบอกว่าปัญหานี้ได้รับการแก้ไขและได้รับรายงานปัญหานี้น้อยลงไปเรื่อยๆใน Access เวอร์ชั่นที่สูงขึ้นๆ   แต่เพื่อความไม่ประมาท ก็ยังเป็นข้อควรปฏิบัติอยู่ว่าควรกำหนด = nothing เสมอๆ

ต้องขอขอบคุณ Leigh Purvis จากเวป www.utteraccess.com ที่ให้ความกระจ่างไว้ ณ ที่นี้ด้วย
@ ประกาศใช้งานเว็บบอร์ดใหม่ => บอร์ดเรียนรู้ Access สำหรับคนไทย
แล้วจะใส่ลิ้งอ้างอิงมาที่โพสต์เก่านี้หรือไม่ก็ตามสะดวกครับ
Time: 0.2331s