ฉันต้องการทราบว่าอะไรคือความแตกต่างระหว่างการจัดสรรหน่วยความจำแบบคงที่และการจัดสรรหน่วยความจำแบบไดนามิก
คุณช่วยอธิบายเรื่องนี้ด้วยตัวอย่างได้ไหม
ฉันต้องการทราบว่าอะไรคือความแตกต่างระหว่างการจัดสรรหน่วยความจำแบบคงที่และการจัดสรรหน่วยความจำแบบไดนามิก
คุณช่วยอธิบายเรื่องนี้ด้วยตัวอย่างได้ไหม
คำตอบ:
การจัดสรรมีสามประเภท ได้แก่ แบบคงที่อัตโนมัติและแบบไดนามิก
การจัดสรรแบบคงที่หมายความว่าหน่วยความจำสำหรับตัวแปรของคุณจะได้รับการจัดสรรเมื่อโปรแกรมเริ่มทำงาน ขนาดจะคงที่เมื่อสร้างโปรแกรม ใช้กับตัวแปรส่วนกลางตัวแปรขอบเขตไฟล์และตัวแปรที่มีคุณสมบัติstatic
ตามฟังก์ชันภายในที่กำหนดไว้
การจัดสรรหน่วยความจำอัตโนมัติเกิดขึ้นสำหรับตัวแปร (ไม่คงที่) ที่กำหนดไว้ภายในฟังก์ชันและโดยปกติจะถูกเก็บไว้ในสแตก (แม้ว่ามาตรฐาน C จะไม่ได้กำหนดว่าจะใช้สแต็ก) คุณไม่จำเป็นต้องสำรองหน่วยความจำเพิ่มเติมโดยใช้หน่วยความจำเหล่านี้ แต่ในทางกลับกันยังมีการควบคุมอายุการใช้งานของหน่วยความจำนี้อย่าง จำกัด เช่น: ตัวแปรอัตโนมัติในฟังก์ชันจะอยู่ที่นั่นจนกว่าฟังก์ชันจะเสร็จสิ้น
void func() {
int i; /* `i` only exists during `func` */
}
การจัดสรรหน่วยความจำแบบไดนามิกแตกต่างกันเล็กน้อย ตอนนี้คุณควบคุมขนาดที่แน่นอนและอายุการใช้งานของตำแหน่งหน่วยความจำเหล่านี้ หากคุณไม่ปล่อยให้ว่างคุณจะพบหน่วยความจำรั่วซึ่งอาจทำให้แอปพลิเคชันของคุณขัดข้องเนื่องจากในบางช่วงเวลาระบบจะไม่สามารถจัดสรรหน่วยความจำเพิ่มเติมได้
int* func() {
int* mem = malloc(1024);
return mem;
}
int* mem = func(); /* still accessible */
ในตัวอย่างด้านบนหน่วยความจำที่จัดสรรยังคงถูกต้องและสามารถเข้าถึงได้แม้ว่าฟังก์ชันจะสิ้นสุดลง เมื่อคุณใช้หน่วยความจำเสร็จแล้วคุณต้องปล่อยให้เป็นอิสระ:
free(mem);
นี่เป็นคำถามสัมภาษณ์มาตรฐาน:
มีการจัดสรรหน่วยความจำที่รันไทม์ใช้calloc()
, malloc()
และเพื่อน ๆ บางครั้งเรียกว่าหน่วยความจำ 'ฮีป' แม้ว่าจะไม่มีส่วนเกี่ยวข้องกับการอ้างอิงโครงสร้างข้อมูลฮีปก็ตาม
int * a = malloc(sizeof(int));
หน่วยความจำฮีปจะคงอยู่จนกว่าfree()
จะถูกเรียก กล่าวอีกนัยหนึ่งคือคุณควบคุมอายุการใช้งานของตัวแปร
นี่คือสิ่งที่เรียกกันโดยทั่วไปว่าหน่วยความจำ 'สแตก' และจะถูกจัดสรรเมื่อคุณเข้าสู่ขอบเขตใหม่ (โดยปกติเมื่อฟังก์ชันใหม่ถูกผลักไปที่ call stack) เมื่อคุณย้ายออกจากขอบเขตค่าของที่อยู่หน่วยความจำอัตโนมัติจะไม่ได้กำหนดและมันเป็นข้อผิดพลาดในการเข้าถึงพวกเขา
int a = 43;
โปรดทราบว่าขอบเขตไม่จำเป็นต้องหมายถึงฟังก์ชัน ขอบเขตสามารถซ้อนกันภายในฟังก์ชันและตัวแปรจะอยู่ในขอบเขตเฉพาะภายในบล็อกที่มีการประกาศ โปรดทราบด้วยว่าไม่ได้ระบุตำแหน่งที่จัดสรรหน่วยความจำนี้ (ในระบบที่มีเหตุผลมันจะอยู่บนสแต็กหรือลงทะเบียนเพื่อการปรับให้เหมาะสม)
มีการจัดสรรที่รวบรวมเวลา*และอายุการใช้งานของตัวแปรในความทรงจำคงที่คืออายุการใช้งานของโปรแกรม
ใน C สามารถจัดสรรหน่วยความจำแบบคงที่ได้โดยใช้static
คีย์เวิร์ด ขอบเขตคือหน่วยคอมไพล์เท่านั้น
สิ่งที่ได้รับน่าสนใจมากขึ้นเมื่อextern
คำหลักที่ถือว่าเป็น เมื่อextern
ตัวแปรที่กำหนดไว้ในหน่วยความจำคอมไพเลอร์จัดสรรสำหรับมัน เมื่อมีการประกาศextern
ตัวแปรคอมไพเลอร์ต้องการให้กำหนดตัวแปรไว้ที่อื่น ความล้มเหลวในการประกาศ / กำหนดตัวแปรจะทำให้เกิดปัญหาการเชื่อมโยงในขณะที่ความล้มเหลวในการประกาศ / กำหนดตัวแปรจะทำให้เกิดปัญหาในการคอมไพล์extern
static
ในขอบเขตไฟล์คำสำคัญแบบคงที่เป็นทางเลือก (นอกฟังก์ชัน):
int a = 32;
แต่ไม่อยู่ในขอบเขตของฟังก์ชัน (ภายในฟังก์ชัน):
static int a = 32;
ในทางเทคนิคextern
และstatic
เป็นสองคลาสที่แยกจากกันของตัวแปรใน C.
extern int a; /* Declaration */
int a; /* Definition */
ค่อนข้างสับสนที่จะบอกว่าหน่วยความจำแบบคงที่ถูกจัดสรรในเวลาคอมไพล์โดยเฉพาะอย่างยิ่งถ้าเราเริ่มพิจารณาว่าเครื่องคอมไพล์และเครื่องโฮสต์อาจไม่เหมือนกันหรืออาจไม่ได้อยู่ในสถาปัตยกรรมเดียวกัน
มันอาจจะดีกว่าที่จะคิดว่าการจัดสรรหน่วยความจำแบบคงที่ถูกจัดการโดยคอมไพเลอร์มากกว่าการจัดสรรที่รวบรวมเวลา
ตัวอย่างเช่นคอมไพเลอร์อาจสร้างdata
ส่วนขนาดใหญ่ในไบนารีที่คอมไพล์แล้วและเมื่อโปรแกรมถูกโหลดในหน่วยความจำที่อยู่ภายในdata
ส่วนของโปรแกรมจะถูกใช้เป็นตำแหน่งของหน่วยความจำที่จัดสรร สิ่งนี้มีข้อเสียที่ชัดเจนในการทำให้ไบนารีที่คอมไพล์มีขนาดใหญ่มากหากใช้หน่วยความจำแบบคงที่จำนวนมาก เป็นไปได้ที่จะเขียนไบนารีหลายกิกะไบต์ที่สร้างขึ้นจากโค้ดน้อยกว่าครึ่งโหล อีกทางเลือกหนึ่งคือให้คอมไพลเลอร์ฉีดรหัสการเริ่มต้นซึ่งจะจัดสรรหน่วยความจำด้วยวิธีอื่นก่อนที่โปรแกรมจะทำงาน รหัสนี้จะแตกต่างกันไปตามแพลตฟอร์มและระบบปฏิบัติการเป้าหมาย ในทางปฏิบัติคอมไพเลอร์สมัยใหม่ใช้ฮิวริสติกส์เพื่อตัดสินใจว่าจะใช้ตัวเลือกใดต่อไปนี้ คุณสามารถลองทำสิ่งนี้ด้วยตัวเองโดยเขียนโปรแกรม C ขนาดเล็กที่จัดสรรอาร์เรย์แบบคงที่ขนาดใหญ่ของรายการ 10k, 1m, 10m, 100m, 1G หรือ 10G สำหรับคอมไพเลอร์จำนวนมากขนาดไบนารีจะเพิ่มขึ้นเรื่อย ๆ ตามขนาดของอาร์เรย์และเมื่อผ่านจุดหนึ่งไป
คลาสหน่วยความจำสุดท้ายคือตัวแปร 'register' ตามที่คาดไว้ตัวแปร register ควรได้รับการจัดสรรบนรีจิสเตอร์ของ CPU แต่การตัดสินใจนั้นถูกปล่อยให้คอมไพเลอร์ คุณไม่สามารถเปลี่ยนตัวแปร register ให้เป็นการอ้างอิงโดยใช้ address-of
register int meaning = 42;
printf("%p\n",&meaning); /* this is wrong and will fail at compile time. */
คอมไพเลอร์สมัยใหม่ส่วนใหญ่ฉลาดกว่าคุณในการเลือกตัวแปรที่ควรใส่ในรีจิสเตอร์ :)
int * a = malloc(sizeof(*a));
แทนเพื่อหลีกเลี่ยงการทำซ้ำประเภทของa
ไฟล์. สิ่งนี้ทำให้ง่ายขึ้นมากหากมีการa
เปลี่ยนแปลงประเภท
การจัดสรรหน่วยความจำแบบคงที่:
การจัดสรรหน่วยความจำแบบไดนามิก:
การจัดสรรหน่วยความจำแบบคงที่:คอมไพลเลอร์จะจัดสรรพื้นที่หน่วยความจำที่ต้องการสำหรับตัวแปรที่ประกาศโดยใช้แอดเดรสของตัวดำเนินการจะได้รับแอดเดรสที่สงวนไว้และแอดเดรสนี้อาจถูกกำหนดให้กับตัวแปรพอยน์เตอร์เนื่องจากตัวแปรที่ประกาศส่วนใหญ่มีหน่วยความจำแบบคงที่ วิธีการกำหนดค่าตัวชี้ให้กับตัวแปรตัวชี้เรียกว่าการจัดสรรหน่วยความจำแบบคงที่ มีการกำหนดหน่วยความจำในช่วงเวลาคอมไพล์
การจัดสรรหน่วยความจำแบบไดนามิก:ใช้ฟังก์ชันเช่น malloc () หรือ calloc () เพื่อรับหน่วยความจำแบบไดนามิกหากใช้ฟังก์ชันเหล่านี้เพื่อรับหน่วยความจำแบบไดนามิกและค่าที่ส่งคืนโดยฟังก์ชันเหล่านี้จะถูกกำหนดให้กับตัวแปรตัวชี้การกำหนดดังกล่าวเรียกว่าหน่วยความจำแบบไดนามิก การจัดสรรหน่วยความจำถูกกำหนดระหว่างเวลาทำงาน
ความแตกต่างระหว่างการจัดสรรหน่วยความจำแบบคงที่และการจัดสรรหน่วยความจำแบบไดนามิก
หน่วยความจำถูกจัดสรรก่อนที่โปรแกรมจะเริ่มทำงาน (ระหว่างการคอมไพล์)
มีการจัดสรรหน่วยความจำระหว่างการทำงานของโปรแกรม
ไม่มีการดำเนินการจัดสรรหน่วยความจำหรือการยกเลิกการจัดสรรระหว่างการดำเนินการ
การผูกหน่วยความจำถูกสร้างขึ้นและถูกทำลายในระหว่างการดำเนินการ
ตัวแปรยังคงจัดสรรอย่างถาวร
จัดสรรเมื่อหน่วยโปรแกรมทำงานอยู่เท่านั้น
ดำเนินการโดยใช้สแต็กและฮีป
ดำเนินการโดยใช้กลุ่มข้อมูล
จำเป็นต้องใช้ตัวชี้ในการเข้าถึงตัวแปร
ไม่จำเป็นต้องมีการจัดสรรพอยน์เตอร์แบบไดนามิก
ดำเนินการเร็วกว่าไดนามิก
การดำเนินการช้ากว่าแบบคงที่
ต้องการพื้นที่หน่วยความจำเพิ่มเติม
ต้องการพื้นที่หน่วยความจำน้อยลง
การจัดสรรหน่วยความจำแบบสแตติกจะถูกจัดสรรหน่วยความจำก่อนดำเนินการโปรแกรม pf ในช่วงเวลาคอมไพล์ การจัดตำแหน่งหน่วยความจำแบบไดนามิกเป็นการจัดตำแหน่งหน่วยความจำระหว่างการทำงานของโปรแกรมในขณะรันไทม์
การจัดสรรหน่วยความจำแบบคงที่ หน่วยความจำที่จัดสรรจะอยู่ในสแต็ก
int a[10];
การจัดสรรหน่วยความจำแบบไดนามิก หน่วยความจำที่จัดสรรจะอยู่ในฮีป
int *a = malloc(sizeof(int) * 10);
และหลังควรเป็นd ฟรีเนื่องจากไม่มี Garbage Collector (GC) ใน C
free(a);