ในกระบวนการใช้ DELPHI เพื่อพัฒนาซอฟต์แวร์ เราเป็นเหมือนกลุ่มวัวและแกะที่มีความสุขบนทุ่งหญ้า เพลิดเพลินกับแสงแดดที่ส่งมาให้เราอย่างอิสระด้วยภาษา Object Pascal และพืชน้ำอันอุดมสมบูรณ์ที่จัดทำโดยตัวควบคุม VCL ต่างๆ มองขึ้นไปบนท้องฟ้าสีครามอันไร้ขอบเขต มองลงไปที่หญ้าอันเขียวขจีบนพื้นโลก ใครจะนึกถึงจักรวาลที่ใหญ่โต และสิ่งใดที่เล็กกว่าโมเลกุลและอะตอม? นั่นเป็นเรื่องของนักปรัชญา ขณะนั้นนักปราชญ์นั่งอยู่บนยอดเขาสูง มองดูความเปลี่ยนแปลงของเนบิวลาแห่งจักรวาล จ้องมองแมลงคลานบนพื้นดิน จู่ๆ ก็หันกลับมาพยักหน้าและยิ้มให้กับฝูงสัตว์กินหญ้าของเรา วัวและแกะ เขาหยิบหญ้าชิ้นหนึ่งใส่ปากเบา ๆ หลับตาแล้วชิมอย่างระมัดระวัง ฉันสงสัยว่าหญ้าชิ้นนี้อยู่ในปากของปราชญ์ว่าอะไร? อย่างไรก็ตาม เขามักจะมีรอยยิ้มที่น่าพอใจบนใบหน้าของเขาเสมอ
การรู้และทำความเข้าใจโลกอะตอมระดับจุลภาคของ DELPHI สามารถช่วยให้เราเข้าใจโครงสร้างการใช้งานระดับมหภาคของ DELPHI ได้อย่างถ่องแท้ ซึ่งจะเป็นการพัฒนาซอฟต์แวร์ของเราในพื้นที่อุดมการณ์ที่กว้างขึ้น มันเหมือนกับว่านิวตันค้นพบการเคลื่อนที่ของวัตถุขนาดมหึมา แต่ก็ประสบปัญหาเพราะเขาไม่รู้ว่าเหตุใดวัตถุจึงเคลื่อนที่เช่นนี้ ในทางกลับกัน ไอน์สไตน์ประสบกับชีวิตที่มีความสุขของทฤษฎีสัมพัทธภาพระหว่างกฎของอนุภาคพื้นฐานกับการเคลื่อนที่ของวัตถุขนาดมหึมา !
ส่วนที่ 1 ถึงวัตถุอะตอม
TObject คืออะไร?
เป็นแกนหลักของสถาปัตยกรรมภาษา Object Pascal และเป็นที่มาของการควบคุม VCL ต่างๆ เราสามารถมอง TObject เป็นหนึ่งในอะตอมที่ประกอบขึ้นเป็นแอปพลิเคชัน DELPHI แน่นอนว่าพวกมันประกอบด้วยอนุภาคที่ละเอียดกว่า เช่น องค์ประกอบไวยากรณ์ Pascal พื้นฐาน
กล่าวกันว่า TObject เป็นอะตอมของโปรแกรม DELPHI เนื่องจาก TObject ได้รับการสนับสนุนภายในโดยคอมไพเลอร์ DELPHI คลาสอ็อบเจ็กต์ทั้งหมดได้มาจาก TObject แม้ว่าคุณจะไม่ได้ระบุ TObject เป็นคลาสระดับบนสุดก็ตาม TObject ถูกกำหนดไว้ในหน่วยระบบซึ่งเป็นส่วนหนึ่งของระบบ ที่จุดเริ่มต้นของหน่วย System.pas มีข้อความแสดงความคิดเห็นนี้:
{ค่าคงที่ที่กำหนดไว้ล่วงหน้า ประเภท ขั้นตอน }
{ และฟังก์ชัน (เช่น True, Integer หรือ }
{Writeln) ไม่มีการประกาศตามจริง}
{ แต่กลับถูกสร้างไว้ในคอมไพเลอร์แทน }
{ และได้รับการปฏิบัติเหมือนมีการประกาศ }
{ ที่จุดเริ่มต้นของหน่วยระบบ }
หมายความว่าหน่วยนี้มีค่าคงที่ ประเภท ขั้นตอน และฟังก์ชันที่กำหนดไว้ล่วงหน้า (เช่น: True, Integer หรือ Writeln) สิ่งเหล่านี้ไม่ได้ประกาศไว้จริง ๆ แต่คอมไพเลอร์มีอยู่ในตัวและถูกใช้เมื่อเริ่มต้นการคอมไพล์ เป็นคำจำกัดความที่กำหนดไว้ คุณสามารถเพิ่มไฟล์ซอร์สโปรแกรมอื่นๆ เช่น Classes.pas หรือ Windows.pas ลงในไฟล์โปรเจ็กต์ของคุณเพื่อคอมไพล์และดีบักซอร์สโค้ด แต่คุณไม่สามารถเพิ่มไฟล์โปรแกรมซอร์ส System.pas ลงในไฟล์โปรเจ็กต์ของคุณเพื่อคอมไพล์ได้อย่างแน่นอน! DELPHI จะรายงานข้อผิดพลาดในการคอมไพล์สำหรับคำจำกัดความที่ซ้ำกันของระบบ!
ดังนั้น TObject จึงเป็นคำจำกัดความที่คอมไพเลอร์กำหนดไว้เป็นการภายใน สำหรับพวกเราที่ใช้ DELPHI ในการพัฒนาโปรแกรม TObject ถือเป็นอะตอม
คำจำกัดความของ TObject ในหน่วยระบบเป็นดังนี้:
TObject = คลาส
ตัวสร้าง สร้าง;
ขั้นตอน ฟรี;
ฟังก์ชั่นคลาส InitInstance (อินสแตนซ์: ตัวชี้): TObject;
ขั้นตอน CleanupInstance;
ฟังก์ชั่น ClassType: TClass;
ฟังก์ชั่นคลาส ClassName: ShortString;
ฟังก์ชั่นคลาส ClassNameIs (ชื่อ const: สตริง): บูลีน;
ฟังก์ชั่นคลาส ClassParent: TClass;
ฟังก์ชั่นคลาส ClassInfo: ตัวชี้;
ฟังก์ชั่นคลาส InstanceSize: Longint;
ฟังก์ชั่นคลาส InheritsFrom (AClass: TClass): บูลีน;
ฟังก์ชั่นคลาส MethodAddress (ชื่อ const: ShortString): ตัวชี้;
ฟังก์ชั่นคลาส MethodName (ที่อยู่: ตัวชี้): ShortString;
ฟังก์ชั่น FieldAddress (ชื่อ const: ShortString): ตัวชี้;
ฟังก์ชั่น GetInterface (const IID: TGUID; ออก Obj): บูลีน;
ฟังก์ชันคลาส GetInterfaceEntry (const IID: TGUID): PInterfaceEntry;
ฟังก์ชันคลาส GetInterfaceTable: PInterfaceTable;
ฟังก์ชั่น SafeCallException (ExceptObject: TObject;
ยกเว้นAddr: ตัวชี้): HResult เสมือน;
ขั้นตอนหลังการก่อสร้างเสมือน;
ขั้นตอนก่อนการทำลายล้าง;
ขั้นตอนการจัดส่ง (ข้อความ var);
ขั้นตอน DefaultHandler (ข้อความ var);
ฟังก์ชันคลาส NewInstance: TObject เสมือน;
ขั้นตอน FreeInstance เสมือน;
destructor ทำลายเสมือน;
จบ;
ต่อไปเราจะค่อยๆ เคาะประตูอะตอมของ TObject เพื่อดูว่าภายในมีโครงสร้างอะไรบ้าง
เรารู้ว่า TObject เป็นคลาสพื้นฐานของวัตถุทั้งหมด แล้ววัตถุคืออะไรกันแน่?
วัตถุใดๆ ใน DELPHI เป็นตัวชี้ ซึ่งระบุพื้นที่ที่วัตถุครอบครองในหน่วยความจำ! แม้ว่าวัตถุจะเป็นพอยน์เตอร์ แต่เมื่อเราอ้างถึงสมาชิกของวัตถุ เราไม่จำเป็นต้องเขียนโค้ด MyObject^.GetName แต่สามารถเขียนได้เฉพาะ MyObject.GetName เท่านั้น นี่คือไวยากรณ์แบบขยายของภาษา Object Pascal และเป็น รองรับโดยคอมไพเลอร์ เพื่อนที่ใช้ C++ Builder มีความชัดเจนมากเกี่ยวกับความสัมพันธ์ระหว่างอ็อบเจ็กต์และพอยน์เตอร์ เนื่องจากอ็อบเจ็กต์ใน C++ Builder ต้องถูกกำหนดให้เป็นตัวชี้ สถานที่ที่ตัวชี้วัตถุชี้คือพื้นที่วัตถุที่วัตถุเก็บข้อมูล มาวิเคราะห์โครงสร้างข้อมูลของพื้นที่หน่วยความจำที่ชี้โดยตัวชี้วัตถุ
4 ไบต์แรกของพื้นที่อ็อบเจ็กต์ชี้ไปที่ตารางที่อยู่เมธอดเสมือน (VMT - ตารางเมธอดเสมือน) ของคลาสอ็อบเจ็กต์ ช่องว่างถัดไปคือช่องว่างสำหรับจัดเก็บข้อมูลสมาชิกของออบเจ็กต์เอง และถูกจัดเก็บในลำดับทั้งหมดตั้งแต่สมาชิกข้อมูลของคลาสบรรพบุรุษดั้งเดิมที่สุดของออบเจ็กต์ไปจนถึงสมาชิกข้อมูลของคลาสอ็อบเจ็กต์ และในลำดับที่ สมาชิกข้อมูลถูกกำหนดไว้ในแต่ละระดับของชั้นเรียน
ตารางเมธอดเสมือนของคลาส (VMT) เก็บที่อยู่โพรซีเดอร์ของเมธอดเสมือนของคลาสทั้งหมดที่ได้รับมาจากคลาสบรรพบุรุษดั้งเดิมของคลาส วิธีการเสมือนของคลาสเป็นวิธีการประกาศด้วยคำสงวน วิธีการเสมือนเป็นกลไกพื้นฐานในการบรรลุความหลากหลายของวัตถุ แม้ว่าวิธีการแบบไดนามิกที่ประกาศด้วยคำสงวนแบบไดนามิกยังสามารถบรรลุความหลากหลายของวัตถุได้ วิธีการดังกล่าวจะไม่ถูกเก็บไว้ในตารางที่อยู่วิธีการเสมือน (VMT) มันเป็นเพียงวิธีการอื่นที่จัดทำโดย Object Pascal ที่สามารถประหยัดพื้นที่การจัดเก็บคลาส แต่ต้องแลกกับความเร็วในการโทร
แม้ว่าเราจะไม่ได้กำหนดวิธีการเสมือนของคลาสเอง แต่ออบเจ็กต์ของคลาสยังคงมีตัวชี้ไปยังตารางที่อยู่ของวิธีการเสมือน แต่ความยาวของรายการที่อยู่จะเป็นศูนย์ อย่างไรก็ตาม วิธีการเสมือนที่กำหนดไว้ใน TObject เช่น Destroy, FreeInstance ฯลฯ จะถูกเก็บไว้ที่ใด ปรากฎว่าที่อยู่วิธีการของพวกเขาถูกจัดเก็บไว้ในช่องว่างชดเชยในทิศทางลบที่สัมพันธ์กับตัวชี้ VMT ในความเป็นจริง พื้นที่ข้อมูลชดเชย 76 ไบต์ในทิศทางลบของตาราง VMT คือโครงสร้างข้อมูลระบบของคลาสอ็อบเจ็กต์ โครงสร้างข้อมูลเหล่านี้เกี่ยวข้องกับคอมไพเลอร์และอาจมีการเปลี่ยนแปลงในเวอร์ชัน DELPHI ในอนาคต
ดังนั้นคุณจึงคิดว่า VMT เป็นโครงสร้างข้อมูลที่เริ่มต้นจากพื้นที่ข้อมูลออฟเซ็ตเชิงลบคือพื้นที่ข้อมูลระบบของ VMT และข้อมูลออฟเซ็ตเชิงบวกของ VMT คือพื้นที่ข้อมูลผู้ใช้ (วิธีการเสมือนที่กำหนดเอง) ตารางที่อยู่) ฟังก์ชั่นและขั้นตอนที่เกี่ยวข้องกับข้อมูลคลาสหรือข้อมูลรันไทม์ของวัตถุที่กำหนดใน TObject โดยทั่วไปจะเกี่ยวข้องกับข้อมูลระบบของ VMT
ข้อมูล VMT แสดงถึงคลาส อันที่จริง VMT ก็คือคลาส! ใน Object Pascal เราใช้ตัวระบุ เช่น TObject, TComponent ฯลฯ เพื่อแสดงคลาสซึ่งนำไปใช้เป็นข้อมูล VMT ตามลำดับภายใน DELPHI จริงๆ แล้วประเภทของคลาสที่กำหนดด้วยคลาสของคำสงวนนั้นเป็นตัวชี้ไปยังข้อมูล VMT ที่เกี่ยวข้อง
สำหรับแอปพลิเคชันของเรา ข้อมูล VMT จะเป็นข้อมูลคงที่ หลังจากที่คอมไพเลอร์รวบรวมแอปพลิเคชันของเราแล้ว ข้อมูลนี้จะถูกกำหนดและเตรียมใช้งาน คำสั่งโปรแกรมที่เราเขียนสามารถเข้าถึงข้อมูลที่เกี่ยวข้องกับ VMT รับข้อมูล เช่น ขนาดของอ็อบเจ็กต์ ชื่อคลาส หรือข้อมูลแอตทริบิวต์รันไทม์ หรือการเรียกเมธอดเสมือน หรืออ่านชื่อและที่อยู่ของเมธอด เป็นต้น
เมื่อวัตถุถูกสร้างขึ้น ระบบจะจัดสรรพื้นที่หน่วยความจำสำหรับวัตถุและเชื่อมโยงวัตถุกับคลาสที่เกี่ยวข้อง ดังนั้น 4 ไบต์แรกในพื้นที่ข้อมูลที่จัดสรรสำหรับวัตถุจะกลายเป็นตัวชี้ไปยังข้อมูลคลาส VMT
มาดูกันว่าวัตถุเกิดและตายอย่างไร การได้เห็นลูกชายวัย 3 ขวบของฉันกระโดดไปมาบนพื้นหญ้า เพราะฉันได้เห็นกระบวนการกำเนิดของชีวิตจึงเข้าใจความหมายและความยิ่งใหญ่ของชีวิตได้อย่างแท้จริง เฉพาะผู้ที่มีประสบการณ์ความตายเท่านั้นที่จะเข้าใจและทะนุถนอมชีวิตมากขึ้น ดังนั้นเรามาทำความเข้าใจกระบวนการสร้างและการตายของวัตถุกันดีกว่า!
เราทุกคนรู้ดีว่าวัตถุที่ง่ายที่สุดสามารถสร้างขึ้นได้โดยใช้คำสั่งต่อไปนี้:
AnObject := TObject.Create;
คอมไพเลอร์ดำเนินการคอมไพล์เป็น:
ขึ้นอยู่กับ VMT ที่สอดคล้องกับ TObject ให้เรียกตัวสร้างการสร้างของ TObject ตัวสร้าง Create เรียกกระบวนการ ClassCreate ของระบบ และกระบวนการ ClassCreate ของระบบเรียกเมธอดเสมือน NewInstance ผ่านคลาส VMT ที่จัดเก็บไว้ในนั้น วัตถุประสงค์ของการเรียกเมธอด NewInstance คือการสร้างพื้นที่อินสแตนซ์ของออบเจ็กต์ เนื่องจากเราไม่ได้ใช้งานเมธอดนี้มากเกินไป จึงเป็น NewInstance ของคลาส TObject เมธอด NewInstance ของคลาส TObjec จะเรียกขั้นตอน GetMem เพื่อจัดสรรหน่วยความจำสำหรับออบเจ็กต์ตามขนาดอินสแตนซ์ของออบเจ็กต์ (InstanceSize) ที่เตรียมใช้งานโดยคอมไพเลอร์ในตาราง VMT จากนั้นเรียกเมธอด InitInstance เพื่อเตรียมใช้งานพื้นที่ที่จัดสรร ในขั้นแรกเมธอด InitInstance จะเตรียมใช้งานพื้นที่อ็อบเจ็กต์ 4 ไบต์แรกโดยเป็นตัวชี้ไปยัง VMT ที่สอดคล้องกับคลาสอ็อบเจ็กต์ จากนั้นจึงล้างพื้นที่ที่เหลือ หลังจากสร้างอินสแตนซ์ของวัตถุแล้ว จะเรียกเมธอดเสมือน AfterConstruction เช่นกัน สุดท้าย ให้บันทึกตัวชี้ที่อยู่ของข้อมูลอินสแตนซ์ออบเจ็กต์ลงในตัวแปร AnObject และด้วยวิธีนี้ ออบเจ็กต์ AnObject จึงถือกำเนิดขึ้น
ในทำนองเดียวกัน วัตถุสามารถถูกทำลายได้โดยใช้คำสั่งต่อไปนี้:
วัตถุ ทำลาย;
ตัวทำลายล้างของ TObject ซึ่งก็คือ Destroy ได้รับการประกาศให้เป็นวิธีการเสมือน ซึ่งเป็นหนึ่งในวิธีการเสมือนที่มีอยู่ในระบบด้วย วิธีการ Destory เรียกวิธีการเสมือน BeforeDestruction ก่อน แล้วจึงเรียกกระบวนการ ClassDestroy ของระบบ กระบวนการ ClassDestory เรียกวิธีการเสมือน FreeInstance ผ่านคลาส VMT และวิธีการ FreeInstance เรียกกระบวนการ FreeMem เพื่อปล่อยพื้นที่หน่วยความจำของวัตถุ เพียงเท่านี้ วัตถุก็หายไปจากระบบ
กระบวนการทำลายล้างวัตถุนั้นง่ายกว่ากระบวนการสร้างวัตถุ เช่นเดียวกับการกำเนิดของชีวิตเป็นกระบวนการตั้งท้องที่ยาวนาน แต่ความตายนั้นค่อนข้างมีอายุสั้น นี่ดูเหมือนจะเป็นกฎเกณฑ์ที่หลีกเลี่ยงไม่ได้
ในระหว่างกระบวนการสร้างและทำลายออบเจ็กต์ ฟังก์ชันเสมือนสองฟังก์ชัน NewInstance และ FreeInstance จะถูกเรียกเพื่อสร้างและปล่อยพื้นที่หน่วยความจำของอินสแตนซ์ออบเจ็กต์ เหตุผลที่ทั้งสองฟังก์ชันนี้ถูกประกาศเป็นฟังก์ชันเสมือนก็เพื่อให้ผู้ใช้มีพื้นที่สำหรับการขยายเมื่อเขียนคลาสอ็อบเจ็กต์พิเศษที่ต้องการให้ผู้ใช้จัดการหน่วยความจำของตนเอง (เช่นในโปรแกรมควบคุมอุตสาหกรรมพิเศษบางโปรแกรม)
การประกาศ AfterConstruction และ BeforeDestruction เป็นฟังก์ชันเสมือนยังช่วยให้คลาสที่ได้รับในอนาคตมีโอกาสที่จะปล่อยให้วัตถุที่เกิดใหม่สูดอากาศบริสุทธิ์ครั้งแรกหลังจากสร้างวัตถุ และเพื่อให้วัตถุสร้างผลพวงที่ตามมาก่อนที่วัตถุจะตาย ทั้งหมดนี้เป็นสิ่งที่สมเหตุสมผล ในความเป็นจริง เหตุการณ์ OnCreate และเหตุการณ์ OnDestroy ของวัตถุ TForm และวัตถุ TDataModule จะถูกทริกเกอร์ตามลำดับในกระบวนการฟังก์ชันเสมือนสองกระบวนการของ TForm และ TDataModule โอเวอร์โหลด
นอกจากนี้ TObjec ยังมีวิธี Free ซึ่งไม่ใช่วิธีเสมือน มีไว้เพื่อปล่อยวัตถุอย่างปลอดภัยเมื่อไม่ชัดเจนว่าวัตถุนั้นว่างเปล่า (ไม่มี) ที่จริงแล้ว ถ้าคุณไม่รู้ว่าออบเจ็กต์นั้นว่างเปล่าหรือไม่ แสดงว่ามีปัญหาเกี่ยวกับตรรกะของโปรแกรมที่ไม่ชัดเจน อย่างไรก็ตาม ไม่มีใครสมบูรณ์แบบและสามารถทำผิดพลาดได้ การใช้แบบฟรีเพื่อหลีกเลี่ยงข้อผิดพลาดโดยไม่ตั้งใจก็เป็นสิ่งที่ดีเช่นกัน อย่างไรก็ตาม การเขียนโปรแกรมที่ถูกต้องไม่สามารถพึ่งพาโซลูชันดังกล่าวเพียงอย่างเดียวได้ เป้าหมายแรกของการเขียนโปรแกรมควรเป็นเพื่อให้แน่ใจว่าโปรแกรมมีความถูกต้องเชิงตรรกะ!
เพื่อนที่สนใจสามารถอ่านโค้ดต้นฉบับของหน่วยระบบได้ ซึ่งมีโค้ดจำนวนมากเขียนเป็นภาษาแอสเซมบลี เพื่อนที่ระมัดระวังจะพบว่าตัวสร้างของ TObject Create และ Destructor Destory ไม่ได้เขียนโค้ดใด ๆ ที่จริงแล้วผ่านหน้าต่าง Debug CPU ในสถานะการดีบักโค้ดแอสเซมบลีของ Create และ Destory สามารถสะท้อนให้เห็นได้อย่างชัดเจน เนื่องจากผู้เชี่ยวชาญที่สร้าง DELPHI ไม่ต้องการให้ผู้ใช้มีสิ่งที่ซับซ้อนมากเกินไป พวกเขาต้องการให้ผู้ใช้เขียนแอปพลิเคชันตามแนวคิดที่เรียบง่าย และซ่อนงานที่ซับซ้อนภายในระบบเพื่อให้พวกเขาดำเนินการ ดังนั้นเมื่อเผยแพร่หน่วย System.pas รหัสของทั้งสองฟังก์ชันนี้จะถูกลบออกเป็นพิเศษเพื่อทำให้ผู้ใช้คิดว่า TObject เป็นแหล่งที่มาของทุกสิ่ง และคลาสที่ผู้ใช้ได้มาจากความว่างเปล่าโดยสมบูรณ์ ซึ่งไม่ผิดในตัวเอง แม้ว่าการอ่านโค้ดที่สำคัญที่สุดของ DELPHI เหล่านี้จะต้องใช้ความรู้ภาษาแอสเซมบลีเพียงเล็กน้อย แต่การอ่านโค้ดดังกล่าวสามารถทำให้เราเข้าใจถึงต้นกำเนิดและการพัฒนาของโลกของ DELPHI ได้ลึกซึ้งยิ่งขึ้น แม้ว่าคุณจะไม่ค่อยเข้าใจมากนัก แต่อย่างน้อยความสามารถในการเข้าใจสิ่งพื้นฐานบางอย่างจะเป็นประโยชน์อย่างมากสำหรับเราในการเขียนโปรแกรม DELPHI
ส่วนที่ 2 TClass Atom
ในหน่วย System.pas นั้น TClass ถูกกำหนดไว้ดังนี้:
TClass = คลาสของ TObject;
หมายความว่า TClass เป็นคลาสของ TObject เนื่องจาก TObject นั้นเป็นคลาส TClass จึงเป็นคลาสที่เรียกว่าคลาส
ตามแนวคิดแล้ว TClass เป็นคลาสประเภทหนึ่ง ซึ่งก็คือคลาส อย่างไรก็ตาม เรารู้ว่าคลาสของ DELPHI เป็นตัวแทนของข้อมูล VMT ดังนั้นคลาสจึงถือเป็นประเภทที่กำหนดไว้สำหรับรายการข้อมูล VMT จริงๆ แล้วคลาสนี้ถือเป็นประเภทตัวชี้ที่ชี้ไปยังข้อมูล VMT!
ในภาษา C++ แบบดั้งเดิมก่อนหน้านี้ ไม่สามารถกำหนดประเภทของคลาสได้ เมื่อคอมไพล์อ็อบเจ็กต์แล้ว จะได้รับการแก้ไข ข้อมูลโครงสร้างของคลาสจะถูกแปลงเป็นรหัสเครื่องสัมบูรณ์ และข้อมูลคลาสที่สมบูรณ์จะไม่มีอยู่ในหน่วยความจำ ภาษาเชิงวัตถุระดับสูงกว่าบางภาษาสามารถรองรับการเข้าถึงแบบไดนามิกและการเรียกใช้ข้อมูลคลาสได้ แต่มักต้องการกลไกการตีความภายในที่ซับซ้อนและทรัพยากรระบบที่มากขึ้น ภาษา Object Pascal ของ DELPHI ดูดซับคุณลักษณะที่ยอดเยี่ยมบางประการของภาษาเชิงวัตถุระดับสูง ในขณะที่ยังคงรักษาข้อได้เปรียบแบบดั้งเดิมของการคอมไพล์โปรแกรมลงในโค้ดเครื่องโดยตรง ซึ่งช่วยแก้ปัญหาฟังก์ชันขั้นสูงและประสิทธิภาพของโปรแกรมได้อย่างสมบูรณ์แบบ
เป็นเพราะ DELPHI เก็บข้อมูลคลาสที่สมบูรณ์ไว้ในแอปพลิเคชัน ซึ่งสามารถจัดเตรียมฟังก์ชันเชิงอ็อบเจ็กต์ขั้นสูง เช่น และ เพื่อแปลงและระบุคลาสในขณะรันไทม์ ซึ่งข้อมูล VMT ของคลาสมีบทบาทหลักที่สำคัญ เพื่อนที่สนใจสามารถอ่านกระบวนการประกอบทั้งสองของ AsClass และ IsClass ในหน่วยระบบ ซึ่งเป็นโค้ดการใช้งานของ as และเป็นตัวดำเนินการเพื่อเพิ่มความเข้าใจในคลาสและข้อมูล VMT ให้ลึกซึ้งยิ่งขึ้น
โลกอะตอมของ DELPHI (2)
คำสำคัญ: Delphi ควบคุมเบ็ดเตล็ด
ส่วนที่ 2 TClass Atom
ในหน่วย System.pas TClass ถูกกำหนดไว้ดังนี้:
TClass = คลาสของ TObject;
หมายความว่า TClass เป็นคลาสของ TObject เนื่องจาก TObject นั้นเป็นคลาส TClass จึงเป็นคลาสที่เรียกว่าคลาส
ตามแนวคิดแล้ว TClass เป็นคลาสประเภทหนึ่ง ซึ่งก็คือคลาส อย่างไรก็ตาม เรารู้ว่าคลาสของ DELPHI เป็นตัวแทนของข้อมูล VMT ดังนั้นคลาสจึงถือเป็นประเภทที่กำหนดไว้สำหรับรายการข้อมูล VMT จริงๆ แล้วคลาสนี้ถือเป็นประเภทตัวชี้ที่ชี้ไปยังข้อมูล VMT!
ในภาษา C++ แบบดั้งเดิมก่อนหน้านี้ ไม่สามารถกำหนดประเภทของคลาสได้ เมื่อคอมไพล์อ็อบเจ็กต์แล้ว จะได้รับการแก้ไข ข้อมูลโครงสร้างของคลาสจะถูกแปลงเป็นรหัสเครื่องสัมบูรณ์ และข้อมูลคลาสที่สมบูรณ์จะไม่มีอยู่ในหน่วยความจำ ภาษาเชิงวัตถุระดับสูงกว่าบางภาษาสามารถรองรับการเข้าถึงแบบไดนามิกและการเรียกใช้ข้อมูลคลาสได้ แต่มักต้องการกลไกการตีความภายในที่ซับซ้อนและทรัพยากรระบบที่มากขึ้น ภาษา Object Pascal ของ DELPHI ดูดซับคุณลักษณะที่ยอดเยี่ยมบางประการของภาษาเชิงวัตถุระดับสูง ในขณะที่ยังคงรักษาข้อได้เปรียบแบบดั้งเดิมของการคอมไพล์โปรแกรมลงในโค้ดเครื่องโดยตรง ซึ่งช่วยแก้ปัญหาฟังก์ชันขั้นสูงและประสิทธิภาพของโปรแกรมได้อย่างสมบูรณ์แบบ
เป็นเพราะ DELPHI เก็บข้อมูลคลาสที่สมบูรณ์ไว้ในแอปพลิเคชัน ซึ่งสามารถจัดเตรียมฟังก์ชันเชิงอ็อบเจ็กต์ขั้นสูง เช่น และ เพื่อแปลงและระบุคลาสในขณะรันไทม์ ซึ่งข้อมูล VMT ของคลาสมีบทบาทหลักที่สำคัญ เพื่อนที่สนใจสามารถอ่านกระบวนการประกอบทั้งสองของ AsClass และ IsClass ในหน่วยระบบ ซึ่งเป็นโค้ดการใช้งานของ as และเป็นตัวดำเนินการเพื่อเพิ่มความเข้าใจในคลาสและข้อมูล VMT ให้ลึกซึ้งยิ่งขึ้น
ด้วยประเภทของคลาส คุณสามารถใช้คลาสเป็นตัวแปรได้ ตัวแปรคลาสสามารถเข้าใจได้ว่าเป็นวัตถุพิเศษ และคุณสามารถเข้าถึงวิธีการของตัวแปรคลาสได้เหมือนกับวัตถุ ตัวอย่างเช่น: ลองมาดูที่ส่วนของโปรแกรมต่อไปนี้:
พิมพ์
TSampleClass = คลาสของ TSampleObject;
TSampleObject = คลาส ( TObject )
สาธารณะ
ตัวสร้าง สร้าง;
destructor ทำลายล้าง;
ฟังก์ชันคลาส GetSampleObjectCount:Integer;
ขั้นตอน GetObjectIndex: จำนวนเต็ม;
จบ;
var
aSampleClass : TSampleClass;
aClass : TClass;
ในโค้ดนี้ เรากำหนดคลาส TSampleObject และประเภทคลาสที่เกี่ยวข้อง TSampleClass รวมถึงตัวแปรคลาสสองตัว aSampleClass และ aClass นอกจากนี้ เรายังกำหนด Constructor, destructor, วิธีการเรียน GetSampleObjectCount และวิธี object GetObjectIndex สำหรับคลาส TSampleObject
ก่อนอื่น มาทำความเข้าใจความหมายของตัวแปรคลาส aSampleClass และ aClass กันก่อน
แน่นอนว่า คุณสามารถถือว่า TSampleObject และ TObject เป็นค่าคงที่และกำหนดให้กับตัวแปร aClass ได้ เช่นเดียวกับการกำหนดค่าคงที่ 123 ค่าให้กับตัวแปรจำนวนเต็ม i ดังนั้นความสัมพันธ์ระหว่างประเภทคลาส คลาสและตัวแปรคลาสจึงเป็นความสัมพันธ์ระหว่างประเภท ค่าคงที่ และตัวแปร แต่อยู่ที่ระดับของคลาสมากกว่าระดับอ็อบเจ็กต์ แน่นอนว่าการกำหนด TObject ให้กับ aSampleClass โดยตรงนั้นไม่ถูกกฎหมาย เนื่องจาก aSampleClass เป็นตัวแปรคลาสของคลาส TSampleObject ที่ได้รับจาก TObject และ TObject ไม่มีคำจำกัดความทั้งหมดที่เข้ากันได้กับประเภท TSampleClass ในทางตรงกันข้าม การกำหนด TSampleObject ให้กับตัวแปร aClass ถือเป็นเรื่องถูกกฎหมาย เนื่องจาก TSampleObject เป็นคลาสที่ได้รับมาจาก TObject และเข้ากันได้กับประเภท TClass สิ่งนี้คล้ายกับความสัมพันธ์การกำหนดและประเภทการจับคู่ของตัวแปรอ็อบเจ็กต์
ถ้าอย่างนั้น เรามาดูกันว่า class method คืออะไร
วิธีการที่เรียกว่าคลาสหมายถึงวิธีการที่เรียกว่าในระดับชั้นเรียน เช่นวิธีการ GetSampleObjectCount ที่กำหนดไว้ข้างต้น ซึ่งเป็นวิธีการประกาศด้วยคลาสคำที่สงวนไว้ วิธีการเรียนแตกต่างจากวิธีการของวัตถุที่ถูกเรียกในระดับวัตถุ วิธีการของวัตถุนั้นคุ้นเคยกับเราอยู่แล้ว และวิธีการของชั้นเรียนมักจะใช้ในระดับการเข้าถึงและการควบคุมลักษณะทั่วไปของวัตถุคลาสทั้งหมดและการจัดการวัตถุจากส่วนกลาง ในคำจำกัดความของ TObject เราสามารถค้นหาวิธีการเรียนได้จำนวนมาก เช่น ClassName, ClassInfo, NewInstance เป็นต้น ในหมู่พวกเขา NewInstance ยังถูกกำหนดให้เป็นเสมือน นั่นคือเมธอดคลาสเสมือน ซึ่งหมายความว่าคุณสามารถเขียนวิธีการปรับใช้ NewInstance ในคลาสย่อยที่ได้รับเพื่อสร้างอินสแตนซ์อ็อบเจ็กต์ของคลาสนั้นด้วยวิธีพิเศษได้
คุณยังสามารถใช้ตัวระบุ self ในวิธีการเรียนได้ แต่ความหมายของมันจะแตกต่างจากวิธีการ self ในวัตถุ self ในเมธอดคลาสแสดงถึงคลาสของตัวเอง นั่นคือ ตัวชี้ไปยัง VMT ในขณะที่เมธอด self ในอ็อบเจ็กต์แสดงถึงตัวอ็อบเจ็กต์เอง นั่นคือ ตัวชี้ไปยังพื้นที่ข้อมูลอ็อบเจ็กต์ แม้ว่าเมธอดคลาสสามารถใช้ได้ในระดับคลาสเท่านั้น คุณยังคงสามารถเรียกเมธอดคลาสผ่านอ็อบเจ็กต์ได้ ตัวอย่างเช่น เมธอดคลาส ClassName ของอ็อบเจ็กต์ TObject สามารถเรียกผ่านคำสั่ง aObject.ClassName ได้ เนื่องจาก 4 ไบต์แรกในพื้นที่ข้อมูลอ็อบเจ็กต์ที่ชี้โดยตัวชี้อ็อบเจ็กต์คือตัวชี้ไปยังคลาส VMT ในทางตรงกันข้าม คุณไม่สามารถเรียกใช้วิธี object ในระดับชั้นเรียนได้ และคำสั่งเช่น TObject.Free จะต้องผิดกฎหมาย
เป็นที่น่าสังเกตว่า Constructor เป็นวิธีการเรียน และ destructor เป็นวิธีการแบบ object!
อะไร ตัวสร้างเป็นวิธีการของคลาสและตัวทำลายเป็นวิธีการของวัตถุ! มีข้อผิดพลาดอะไรบ้าง?
คุณจะเห็นว่าเมื่อคุณสร้างออบเจ็กต์ คุณใช้คำสั่งที่คล้ายกับข้อความต่อไปนี้อย่างชัดเจน:
aObject := TObject.Create;
เห็นได้ชัดว่าเรียกวิธีการสร้างของคลาส TObject เมื่อลบวัตถุให้ใช้คำสั่งต่อไปนี้:
aObject.ทำลาย;
แม้ว่าคุณจะใช้วิธีการอิสระเพื่อปล่อยวัตถุ วิธีการทำลายของวัตถุจะถูกเรียกทางอ้อม
เหตุผลนั้นง่ายมาก ก่อนที่ Object จะถูกสร้างขึ้น วัตถุนั้นยังไม่มีอยู่ มีเพียงคลาสเท่านั้นที่มีอยู่ ในทางตรงกันข้าม การลบวัตถุจะต้องลบวัตถุที่มีอยู่ วัตถุนั้นถูกปล่อย ไม่ใช่คลาส
สุดท้ายนี้ เรามาหารือเกี่ยวกับปัญหาของตัวสร้างที่สมมติขึ้นมา
ในภาษา C++ ดั้งเดิม สามารถใช้ตัวทำลายเสมือนได้ แต่การนำตัวสร้างเสมือนไปใช้นั้นเป็นปัญหาที่ยาก เพราะในภาษา C++ ดั้งเดิมไม่มีประเภทคลาส อินสแตนซ์ของออบเจ็กต์โกลบอลมีอยู่ในพื้นที่ข้อมูลโกลบอล ณ เวลาคอมไพล์ และออบเจ็กต์ของฟังก์ชันในเครื่องก็ถูกแมปในพื้นที่สแต็ก ณ เวลาคอมไพล์ แม้แต่ออบเจ็กต์ที่สร้างขึ้นแบบไดนามิกก็ยังถูกวางในโครงสร้างคลาสคงที่โดยใช้ตัวดำเนินการใหม่ ในพื้นที่ฮีป และตัวสร้างเป็นเพียงวิธีวัตถุที่เตรียมใช้งานอินสแตนซ์ของวัตถุที่สร้างขึ้น ไม่มีเมธอดคลาสจริงในภาษา C++ ดั้งเดิม แม้ว่าสิ่งที่เรียกว่าเมธอดคลาสแบบสแตติกสามารถกำหนดได้ แต่ท้ายที่สุดแล้วเมธอดเหล่านั้นจะถูกนำไปใช้เป็นฟังก์ชันโกลบอลพิเศษ ไม่ต้องพูดถึงเมธอดคลาสเสมือนที่สามารถกำหนดเป้าหมายเฉพาะออบเจ็กต์เท่านั้น กรณีที่มีประสิทธิภาพ ดังนั้น ภาษา C++ แบบดั้งเดิมจึงเชื่อว่าก่อนที่จะสร้างอินสแตนซ์ออบเจ็กต์เฉพาะ เป็นไปไม่ได้ที่จะสร้างออบเจ็กต์เองตามออบเจ็กต์ที่จะสร้างขึ้น มันเป็นไปไม่ได้เลยจริงๆ เพราะสิ่งนี้จะสร้างความขัดแย้งที่ขัดแย้งในตัวเองในทางตรรกะ!
อย่างไรก็ตาม เป็นเพราะแนวคิดหลักของข้อมูลประเภทคลาสไดนามิก วิธีการคลาสเสมือนอย่างแท้จริง และตัวสร้างที่นำไปใช้ตามคลาสใน DELPHI ที่ทำให้ตัวสร้างเสมือนสามารถนำไปใช้ได้ วัตถุถูกสร้างขึ้นโดยชั้นเรียน วัตถุนั้นเหมือนกับทารกที่กำลังเติบโต และชั้นเรียนก็คือแม่ของมันเอง ตัวทารกเองก็ไม่รู้ว่าเขาจะกลายเป็นคนแบบไหนในอนาคต แต่แม่ใช้วิธีการเรียนรู้ของตนเองเพื่อฝึกฝนลูกที่แตกต่างกัน . คนก็มีหลักการเหมือนกัน
อยู่ในคำจำกัดความของคลาส TComponent ที่ตัวสร้าง Create ถูกกำหนดให้เป็นเสมือน เพื่อให้การควบคุมประเภทต่างๆ สามารถใช้วิธีการก่อสร้างของตนเองได้ นี่คือความยิ่งใหญ่ของแนวคิด เช่น คลาสที่สร้างโดย TClass และความยิ่งใหญ่ของ DELPHI
-
บทที่ 3 มุมมองของเวลาและพื้นที่ใน WIN32
พ่อแก่ของฉันมองดูหลานชายตัวน้อยของเขากำลังเล่นของเล่นอยู่บนพื้น แล้วพูดกับฉันว่า "เด็กคนนี้ก็เหมือนกับคุณเมื่อตอนที่คุณยังเป็นเด็ก เขาชอบแยกของออกจากกันและหยุดหลังจากเห็นมันจนจบเท่านั้น" " เมื่อนึกถึงสมัยเด็กๆ ฉันมักจะรื้อรถของเล่น นาฬิกาปลุกเล็กๆ กล่องดนตรี ฯลฯ และมักถูกแม่ดุบ่อยๆ
ครั้งแรกที่ฉันเข้าใจหลักการพื้นฐานของคอมพิวเตอร์เกี่ยวกับกล่องดนตรีที่ฉันแยกออกมา มันอยู่ในหนังสือการ์ตูนตอนที่ฉันอยู่มัธยมปลาย ชายชรามีหนวดเคราสีขาวกำลังอธิบายทฤษฎีของเครื่องจักรอัจฉริยะ และลุงมีหนวดกำลังพูดถึงคอมพิวเตอร์และกล่องดนตรี พวกเขากล่าวว่าหน่วยประมวลผลกลางของคอมพิวเตอร์คือแถวของกกดนตรีที่ใช้สำหรับการออกเสียงในกล่องดนตรี และโปรแกรมคอมพิวเตอร์ก็คือก้อนที่อัดแน่นอยู่บนกระบอกเล็กในกล่องดนตรี การหมุนของกระบอกเล็กนั้นเทียบเท่ากัน ไปจนถึงการหมุนของหน่วยประมวลผลกลาง การเคลื่อนไหวตามธรรมชาติของตัวชี้คำสั่ง ในขณะที่ปุ่มที่แสดงถึงเสียงดนตรีบนกระบอกสูบขนาดเล็กจะควบคุมการสั่นสะเทือนของกกดนตรีเพื่อสร้างคำสั่งที่เทียบเท่ากับการทำงานของโปรแกรมโดยโปรเซสเซอร์กลาง กล่องดนตรีส่งเสียงทำนองอันไพเราะซึ่งเล่นตามโน้ตเพลงที่ช่างฝีมือสลักไว้บนกระบอกสูบขนาดเล็ก คอมพิวเตอร์จะประมวลผลที่ซับซ้อนตามโปรแกรมที่ตั้งโปรแกรมไว้ล่วงหน้าโดยโปรแกรมเมอร์ หลังจากที่ฉันเรียนมหาวิทยาลัย ฉันได้เรียนรู้ว่าชายชราที่มีหนวดเคราสีขาวคือทัวริงยักษ์ใหญ่ด้านวิทยาศาสตร์ ทฤษฎีไฟไนต์ออโตมาตาของเขาส่งเสริมการพัฒนาของการปฏิวัติข้อมูลทั้งหมด และลุงที่มีหนวดเป็นบิดาแห่งคอมพิวเตอร์ ฟอน นอยมันน์ สถาปัตยกรรมคอมพิวเตอร์ยังคงเป็นโครงสร้างสถาปัตยกรรมหลักของคอมพิวเตอร์ กล่องดนตรีไม่ได้ถูกรื้อออกโดยเปล่าประโยชน์ แม่ก็วางใจได้
ด้วยความเข้าใจที่เรียบง่ายและลึกซึ้งเท่านั้นที่เราสามารถสร้างการสร้างสรรค์ที่ลึกซึ้งและรัดกุมได้
ในบทนี้ เราจะพูดถึงแนวคิดพื้นฐานที่เกี่ยวข้องกับการเขียนโปรแกรมของเราในระบบปฏิบัติการ Windows 32 บิต และสร้างมุมมองเวลาและพื้นที่ที่ถูกต้องใน WIN32 ฉันหวังว่าหลังจากอ่านบทนี้แล้ว เราจะมีความเข้าใจอย่างลึกซึ้งยิ่งขึ้นเกี่ยวกับโปรแกรม กระบวนการ และเธรด เข้าใจหลักการของไฟล์ปฏิบัติการ ไลบรารีลิงก์แบบไดนามิกและแพ็คเกจรันไทม์ และเห็นความจริงเกี่ยวกับข้อมูลส่วนกลาง ข้อมูลในเครื่อง และพารามิเตอร์ในหน่วยความจำได้อย่างชัดเจน .
ส่วนที่ 1 การทำความเข้าใจกระบวนการ
เนื่องจากเหตุผลทางประวัติศาสตร์ Windows จึงมาจาก DOS ในยุคดอสเรามักจะมีแต่แนวคิดเรื่องโปรแกรม แต่ไม่มีแนวคิดเรื่องกระบวนการ ในเวลานั้น เฉพาะระบบปฏิบัติการทั่วไป เช่น UNIX และ VMS เท่านั้นที่มีแนวคิดเกี่ยวกับกระบวนการ และหลายกระบวนการหมายถึงมินิคอมพิวเตอร์ เทอร์มินัล และผู้ใช้หลายราย ซึ่งหมายถึงเงินด้วย โดยส่วนใหญ่ ฉันสามารถใช้ได้เฉพาะไมโครคอมพิวเตอร์และระบบ DOS ที่ค่อนข้างถูกเท่านั้น เมื่อฉันกำลังศึกษาระบบปฏิบัติการ ฉันเพิ่งเริ่มสัมผัสกับกระบวนการและมินิคอมพิวเตอร์
มันเป็นหลังจาก Windows 3 เท่านั้น ในอดีตภายใต้ DOS สามารถดำเนินการได้เพียงโปรแกรมเดียวในเวลาเดียวกัน แต่สำหรับ Windows สามารถดำเนินการได้หลายโปรแกรมพร้อมกัน ขณะรันโปรแกรมภายใต้ DOS โปรแกรมเดียวกันจะไม่สามารถดำเนินการพร้อมกันได้ แต่สำหรับ Windows โปรแกรมเดียวกันสามารถทำงานพร้อมกันได้มากกว่าสองชุด และแต่ละสำเนาของโปรแกรมที่ทำงานอยู่นั้นเป็นกระบวนการ เพื่อให้แม่นยำยิ่งขึ้น การเรียกใช้โปรแกรมแต่ละครั้งจะสร้างงาน และแต่ละงานถือเป็นกระบวนการ
เมื่อเข้าใจโปรแกรมและกระบวนการต่างๆ กัน คำว่า โปรแกรม ก็สามารถหมายถึงสิ่งที่คงที่ได้ โปรแกรมทั่วไปคือโค้ดคงที่และข้อมูลที่ประกอบด้วยไฟล์ EXE หรือไฟล์ EXE บวกกับไฟล์ DLL หลายไฟล์ กระบวนการคือการรันโปรแกรมซึ่งเป็นโค้ดและข้อมูลการเปลี่ยนแปลงแบบไดนามิกที่ทำงานแบบไดนามิกในหน่วยความจำ เมื่อจำเป็นต้องรันโปรแกรมแบบคงที่ ระบบปฏิบัติการจะจัดเตรียมพื้นที่หน่วยความจำบางส่วนสำหรับการดำเนินการนี้ ถ่ายโอนรหัสโปรแกรมและข้อมูลแบบคงที่ไปยังพื้นที่หน่วยความจำเหล่านี้ และเปลี่ยนตำแหน่งและแมปรหัสโปรแกรมและข้อมูลในพื้นที่นี้ ดำเนินการภายในจึงสร้างกระบวนการแบบไดนามิก
โปรแกรมเดียวกันที่ทำงานพร้อมกันสองชุดหมายความว่ามีพื้นที่กระบวนการสองช่องในหน่วยความจำระบบ แต่ฟังก์ชันของโปรแกรมเหมือนกัน แต่อยู่ในสถานะที่เปลี่ยนแปลงแบบไดนามิกต่างกัน
ในแง่ของระยะเวลาการทำงานของกระบวนการ แต่ละกระบวนการจะดำเนินการในเวลาเดียวกัน คำศัพท์ทางวิชาชีพเรียกว่าการดำเนินการแบบขนานหรือการดำเนินการพร้อมกัน แต่นี่เป็นความรู้สึกผิวเผินที่ระบบปฏิบัติการมอบให้เรา ที่จริงแล้ว แต่ละกระบวนการจะดำเนินการในลักษณะแบ่งเวลา กล่าวคือ แต่ละกระบวนการผลัดกันใช้เวลาของ CPU เพื่อดำเนินการคำสั่งโปรแกรมของกระบวนการ สำหรับ CPU คำสั่งของกระบวนการเดียวเท่านั้นที่จะดำเนินการในเวลาเดียวกัน ระบบปฏิบัติการเป็นตัวจัดการที่อยู่เบื้องหลังการทำงานของกระบวนการตามกำหนดเวลา โดยจะบันทึกและสลับสถานะปัจจุบันของแต่ละกระบวนการที่ดำเนินการใน CPU เพื่อให้แต่ละกระบวนการตามกำหนดเวลาคิดว่ากำลังทำงานอย่างสมบูรณ์และต่อเนื่อง เนื่องจากการกำหนดเวลาการแบ่งปันเวลาของกระบวนการต่างๆ นั้นรวดเร็วมาก จึงทำให้เรารู้สึกว่ากระบวนการทั้งหมดกำลังทำงานอยู่ในเวลาเดียวกัน ในความเป็นจริง การทำงานพร้อมกันอย่างแท้จริงเป็นไปได้เฉพาะในสภาพแวดล้อมฮาร์ดแวร์ที่มี CPU หลายตัวเท่านั้น เมื่อเราพูดถึงเธรดในภายหลัง เราจะพบว่าเธรดคือสิ่งที่ขับเคลื่อนกระบวนการอย่างแท้จริง และที่สำคัญกว่านั้นคือเธรดเหล่านี้ให้พื้นที่กระบวนการ
ในแง่ของพื้นที่ที่ถูกครอบครองโดยกระบวนการ แต่ละพื้นที่กระบวนการค่อนข้างเป็นอิสระ และแต่ละกระบวนการทำงานในพื้นที่อิสระของตัวเอง โปรแกรมมีทั้งพื้นที่โค้ดและพื้นที่ข้อมูล ทั้งโค้ดและข้อมูลใช้พื้นที่กระบวนการ Windows จัดสรรหน่วยความจำจริงสำหรับพื้นที่ข้อมูลที่แต่ละกระบวนการต้องการ และโดยทั่วไปจะใช้วิธีการแบ่งปันสำหรับพื้นที่โค้ด โดยแมปหนึ่งโค้ดของโปรแกรมกับหลายกระบวนการของโปรแกรม ซึ่งหมายความว่าหากโปรแกรมมีโค้ด 100K และต้องการพื้นที่ข้อมูล 100K ซึ่งหมายความว่าต้องใช้พื้นที่กระบวนการทั้งหมด 200K ระบบปฏิบัติการจะจัดสรรพื้นที่กระบวนการ 200K ในครั้งแรกที่รันโปรแกรม และ 200K ของกระบวนการ พื้นที่จะถูกจัดสรรเป็นครั้งที่สองที่รันโปรแกรม เมื่อกระบวนการเริ่มต้น ระบบปฏิบัติการจะจัดสรรพื้นที่ข้อมูลเพียง 100K เท่านั้น ในขณะที่พื้นที่รหัสแบ่งพื้นที่ของกระบวนการก่อนหน้า
ข้างต้นคือมุมมองเวลาและพื้นที่พื้นฐานของกระบวนการในระบบปฏิบัติการ Windows ที่จริงแล้ว มีความแตกต่างอย่างมากในมุมมองเวลาและพื้นที่ของกระบวนการระหว่างระบบปฏิบัติการ Windows 16 บิตและ 32 บิต
ในแง่ของเวลา การจัดการกระบวนการของระบบปฏิบัติการ Windows 16 บิต เช่น Windows 3.x นั้นง่ายมาก จริงๆ แล้วเป็นเพียงระบบปฏิบัติการการจัดการแบบหลายงาน นอกจากนี้ การกำหนดเวลางานของระบบปฏิบัติการเป็นแบบพาสซีฟ หากงานไม่ละทิ้งการประมวลผลข้อความ ระบบปฏิบัติการต้องรอ เนื่องจากข้อบกพร่องในการจัดการกระบวนการของระบบ Windows 16 บิต เมื่อกระบวนการทำงาน กระบวนการนั้นจะครอบครองทรัพยากรของ CPU โดยสมบูรณ์ ในสมัยนั้น เพื่อให้ Windows 16 บิตมีโอกาสกำหนดเวลางานอื่นๆ Microsoft ยกย่องนักพัฒนาแอปพลิเคชัน Windows ที่เป็นโปรแกรมเมอร์ที่มีใจกว้าง ดังนั้นพวกเขาจึงเต็มใจเขียนโค้ดเพิ่มอีกสองสามบรรทัดเพื่อมอบเป็นของขวัญ ระบบปฏิบัติการ ในทางตรงกันข้าม ระบบปฏิบัติการ WIN32 เช่น Windows 95 และ NT มีความสามารถของระบบปฏิบัติการแบบหลายกระบวนการและแบบมัลติทาสกิ้งอย่างแท้จริง กระบวนการใน Win32 ถูกกำหนดโดยระบบปฏิบัติการอย่างสมบูรณ์ การพูดอย่างเคร่งครัดระบบปฏิบัติการ Windows 16 บิตไม่สามารถถือได้ว่าเป็นระบบปฏิบัติการที่สมบูรณ์ แต่ระบบปฏิบัติการ WIN32 32 บิตเป็นระบบปฏิบัติการที่แท้จริง แน่นอนว่า Microsoft จะไม่พูดว่า Win32 ทำขึ้นสำหรับข้อบกพร่องของหน้าต่าง 16 บิต แต่อ้างว่า Win32 ใช้เทคโนโลยีขั้นสูงที่เรียกว่า
จากมุมมองของพื้นที่แม้ว่าพื้นที่กระบวนการในระบบปฏิบัติการ Windows 16 บิตนั้นค่อนข้างอิสระ แต่กระบวนการสามารถเข้าถึงพื้นที่ข้อมูลของกันและกันได้อย่างง่ายดาย เนื่องจากกระบวนการเหล่านี้เป็นส่วนข้อมูลที่แตกต่างกันในพื้นที่ทางกายภาพเดียวกันและการดำเนินการที่อยู่ที่ไม่เหมาะสมสามารถทำให้การอ่านและการเขียนพื้นที่ไม่ถูกต้องและทำให้ระบบปฏิบัติการขัดข้อง อย่างไรก็ตามในระบบปฏิบัติการ WIN32 แต่ละพื้นที่กระบวนการมีความเป็นอิสระอย่างสมบูรณ์ Win32 ให้แต่ละกระบวนการมีพื้นที่ที่อยู่เสมือนจริงและต่อเนื่องสูงถึง 4G พื้นที่ที่อยู่ต่อเนื่องที่เรียกว่าแต่ละกระบวนการมีพื้นที่ที่อยู่จาก $ 00000000 ถึง $ FFFFFFFF มากกว่าพื้นที่แบ่งส่วนของหน้าต่าง 16 บิต ใน Win32 คุณไม่ต้องกังวลเกี่ยวกับการดำเนินการอ่านและเขียนของคุณโดยไม่ได้ตั้งใจส่งผลกระทบต่อข้อมูลในพื้นที่กระบวนการอื่น ๆ และคุณไม่ต้องกังวลเกี่ยวกับกระบวนการอื่น ๆ ที่จะคุกคามงานของคุณ ในเวลาเดียวกันพื้นที่เสมือนจริง 4G อย่างต่อเนื่องที่จัดทำโดย Win32 สำหรับกระบวนการของคุณคือหน่วยความจำทางกายภาพที่แมปกับคุณโดยระบบปฏิบัติการพร้อมการสนับสนุนของฮาร์ดแวร์ . ความทรงจำทางกายภาพ
ส่วนที่ 2 พื้นที่กระบวนการ
เมื่อเราใช้ Delphi เพื่อเขียนแอปพลิเคชัน Win32 เราไม่ค่อยสนใจเกี่ยวกับโลกภายในของกระบวนการเมื่อมันทำงาน เนื่องจาก Win32 ให้พื้นที่กระบวนการเสมือนจริง 4G สำหรับกระบวนการของเราบางทีแอปพลิเคชั่นที่ใหญ่ที่สุดในโลกในปัจจุบันใช้ส่วนหนึ่งของมันเท่านั้น ดูเหมือนว่าพื้นที่กระบวนการไม่ จำกัด แต่พื้นที่กระบวนการ 4G เป็นเสมือนจริงและหน่วยความจำจริงของเครื่องของคุณอาจยังห่างไกลจากสิ่งนี้ แม้ว่ากระบวนการดังกล่าวจะมีพื้นที่กว้างใหญ่ แต่โปรแกรมอัลกอริทึมที่ซับซ้อนบางโปรแกรมจะยังไม่สามารถทำงานได้เนื่องจากสแต็กล้นโดยเฉพาะอย่างยิ่งโปรแกรมที่มีอัลกอริทึมแบบเรียกซ้ำจำนวนมาก
ดังนั้นความเข้าใจในเชิงลึกเกี่ยวกับโครงสร้างของพื้นที่กระบวนการ 4G ความสัมพันธ์กับหน่วยความจำทางกายภาพ ฯลฯ จะช่วยให้เราเข้าใจโลกอวกาศของ Win32 อย่างชัดเจนยิ่งขึ้นเพื่อให้เราสามารถใช้วิธีการที่ถูกต้องในงานพัฒนาจริง . โลกทัศน์และวิธีการเพื่อแก้ปัญหาที่ยากลำบากต่างๆ
ต่อไปเราจะใช้การทดลองง่ายๆเพื่อทำความเข้าใจโลกภายในของพื้นที่กระบวนการของ Win32 สิ่งนี้อาจต้องใช้ความรู้เกี่ยวกับการลงทะเบียนถ้วยและภาษาแอสเซมบลี แต่ฉันพยายามอธิบายด้วยภาษาง่าย ๆ
เมื่อ Delphi เริ่มต้นโครงการโครงการ 1 จะถูกสร้างขึ้นโดยอัตโนมัติและเราจะเริ่มต้นด้วย ตั้งค่าเบรกพอยต์ได้ทุกที่ในโปรแกรมดั้งเดิมของ Project1.dpr ตั้งค่าเบรกพอยต์ที่ประโยคเริ่มต้น จากนั้นเรียกใช้โปรแกรมและจะหยุดโดยอัตโนมัติเมื่อถึงจุดพัก ในเวลานี้เราสามารถเปิดหน้าต่าง CPU ในเครื่องมือการดีบักเพื่อสังเกตโครงสร้างภายในของพื้นที่กระบวนการ
การลงทะเบียนตัวชี้คำสั่งปัจจุบัน EIP หยุดที่ $ 0043E4B8 Process Space ซึ่งมีพื้นที่ $ 00000000 ไปยังพื้นที่ที่อยู่เล็ก ๆ น้อย ๆ สำหรับ $ FFFFFFFF
ในกล่องคำสั่งในหน้าต่าง CPU คุณสามารถค้นหาเนื้อหาของพื้นที่กระบวนการ เมื่อดูเนื้อหาของพื้นที่น้อยกว่า $ 00400000 คุณจะพบเครื่องหมายคำถาม "????" ที่ปรากฏในเนื้อหาน้อยกว่า $ 00400000 หากคุณดูค่าเลขฐานสิบหกของ Hinstance ตัวแปรทั่วโลกในเวลานี้คุณจะพบว่ามันเป็น $ 00400000 ด้วยเช่นกัน แม้ว่า Hinstance จะสะท้อนให้เห็นถึงการจัดการอินสแตนซ์ของกระบวนการในความเป็นจริงมันเป็นค่าที่อยู่เริ่มต้นเมื่อโปรแกรมถูกโหลดลงในหน่วยความจำและในหน้าต่าง 16 บิต ดังนั้นเราสามารถคิดได้ว่าโปรแกรมของกระบวนการโหลดเริ่มต้นจาก $ 00400000 นั่นคือพื้นที่เริ่มต้นจาก 4M ในพื้นที่เสมือน 4G คือพื้นที่ที่โปรแกรมโหลด
จาก $ 00400000 เป็นต้นไปและก่อน $ 0044D000 ส่วนใหญ่เป็นพื้นที่ที่อยู่ของรหัสโปรแกรมและข้อมูลทั่วโลก ในกล่องสแต็กในหน้าต่าง CPU คุณสามารถดูที่อยู่ของสแต็กปัจจุบัน ในทำนองเดียวกันคุณจะพบว่าพื้นที่ที่อยู่สแต็กปัจจุบันอยู่ใน $ 0067B000 ถึง $ 00680000 โดยมีความยาว $ 5,000 ในความเป็นจริงขนาดพื้นที่สแต็กขั้นต่ำของกระบวนการคือ $ 5,000 ซึ่งได้มาจากค่าขนาดสแต็กขั้นต่ำที่ตั้งไว้ในหน้า linker ของ ProjectOptions เมื่อรวบรวมโปรแกรม Delphi บวก $ 1,000 สแต็กเติบโตจากที่อยู่ระดับสูงไปด้านล่าง พื้นที่กระบวนการ เมื่อรวบรวมโปรแกรม Delphi คุณสามารถควบคุมพื้นที่สแต็กสูงสุดที่สามารถเพิ่มขึ้นได้โดยการตั้งค่าขนาดสแต็คสูงสุดในหน้า linker ใน ProjectOptions โดยเฉพาะอย่างยิ่งในโปรแกรมที่มีความสัมพันธ์การเรียกรูทีนย่อยลึกหรือใช้อัลกอริทึมแบบเรียกซ้ำค่าของขนาดสแต็กสูงสุดจะต้องตั้งค่าอย่างสมเหตุสมผล เนื่องจากการเรียกรูทีนย่อยต้องใช้พื้นที่สแต็กและหลังจากสแต็กหมดระบบจะทำให้เกิดข้อผิดพลาด "สแต็กล้น"
ดูเหมือนว่าพื้นที่กระบวนการหลังจากพื้นที่สแต็กควรเป็นพื้นที่ว่าง ในความเป็นจริงนี่ไม่ใช่กรณี ดูเหมือนว่ากระบวนการนี้สามารถเป็นเจ้าของพื้นที่ 2G ได้จริงๆ ในความเป็นจริงพื้นที่ที่กระบวนการสามารถเป็นเจ้าของได้นั้นไม่ได้เป็น 2G เนื่องจากพื้นที่ 4M จาก $ 00000000 ถึง $ 00400000 เป็นพื้นที่ที่ จำกัด เช่นกัน
แต่ไม่ว่าจะเกิดอะไรขึ้นที่อยู่ที่กระบวนการของเราสามารถใช้งานได้ยังคงกว้างมาก โดยเฉพาะอย่างยิ่งหลังจากพื้นที่สแต็กและระหว่าง $ 80,000,000 มันเป็นสนามรบหลักของพื้นที่กระบวนการ พื้นที่หน่วยความจำที่จัดสรรโดยกระบวนการจากระบบจะถูกแมปไปยังพื้นที่นี้ไลบรารีลิงก์แบบไดนามิกที่โหลดโดยกระบวนการจะถูกแมปไปยังพื้นที่นี้พื้นที่สแต็กเธรดของเธรดใหม่จะถูกแมปไปยังพื้นที่นี้เกือบทั้งหมด การดำเนินการที่เกี่ยวข้องกับการจัดสรรหน่วยความจำทั้งหมดจะถูกแมปกับพื้นที่นี้ โปรดทราบว่าการแมปที่กล่าวถึงที่นี่หมายถึงการติดต่อระหว่างหน่วยความจำจริงและพื้นที่เสมือนจริงนี้ ???? ".