malloc () และ free () ทำงานอย่างไร


276

ฉันต้องการทราบวิธีการmallocและการfreeทำงาน

int main() {
    unsigned char *p = (unsigned char*)malloc(4*sizeof(unsigned char));
    memset(p,0,4);
    strcpy((char*)p,"abcdabcd"); // **deliberately storing 8bytes**
    cout << p;
    free(p); // Obvious Crash, but I need how it works and why crash.
    cout << p;
    return 0;
}

ฉันจะขอบคุณจริง ๆ ถ้าคำตอบอยู่ในระดับความลึกในระดับหน่วยความจำถ้าเป็นไปได้


5
ไม่ควรขึ้นอยู่กับคอมไพเลอร์และรันไทม์ไลบรารีที่ใช้จริงหรือ
Vilx-

9
ที่จะขึ้นอยู่กับการใช้งาน CRT ดังนั้นคุณไม่สามารถพูดคุยได้
Naveen

58
strcpy นั้นเขียน 9 ไบต์ไม่ใช่ 8 อย่าลืม NULL terminator ;-)
Evan Teran


2
@ LưuVĩnhPhúcนั่นคือ C ++ หมายเหตุcout <<
Braden Best

คำตอบ:


385

ตกลงคำตอบบางอย่างเกี่ยวกับ malloc ถูกโพสต์แล้ว

ส่วนที่น่าสนใจคือการทำงานของฟรี (และในทิศทางนี้ malloc ก็สามารถเข้าใจได้ดีขึ้นเช่นกัน)

ในการใช้งาน malloc / ฟรีจำนวนมากโดยปกติแล้วฟรีจะไม่ส่งคืนหน่วยความจำไปยังระบบปฏิบัติการ (หรืออย่างน้อยก็ในกรณีที่หายาก) เหตุผลก็คือคุณจะได้รับช่องว่างในกองของคุณและดังนั้นจึงสามารถเกิดขึ้นได้ว่าคุณเพิ่งเสร็จจาก 2 หรือ 4 GB ของหน่วยความจำเสมือนที่มีช่องว่าง สิ่งนี้ควรหลีกเลี่ยงเนื่องจากเมื่อหน่วยความจำเสมือนเสร็จสิ้นคุณจะมีปัญหาใหญ่มาก อีกเหตุผลคือระบบปฏิบัติการสามารถจัดการหน่วยความจำที่มีขนาดและการจัดตำแหน่งที่เฉพาะเจาะจงเท่านั้น โดยเฉพาะอย่างยิ่ง: โดยปกติระบบปฏิบัติการสามารถจัดการได้เฉพาะบล็อกที่ตัวจัดการหน่วยความจำเสมือนเท่านั้นที่สามารถจัดการได้ (ส่วนใหญ่จะทวีคูณเป็น 512 ไบต์เช่น 4KB)

ดังนั้นการคืน 40 ไบต์ไปยังระบบปฏิบัติการจะไม่ทำงาน ดังนั้นฟรีทำอะไร

ฟรีจะวางบล็อกหน่วยความจำในรายการบล็อกฟรีของตัวเอง โดยปกติจะพยายามรวมบล็อกที่อยู่ติดกันในพื้นที่ที่อยู่ รายการบล็อกฟรีเป็นเพียงรายการวงกลมของหน่วยความจำที่มีข้อมูลการดูแลระบบบางอย่างในการเริ่มต้น นี่คือเหตุผลว่าทำไมการจัดการองค์ประกอบหน่วยความจำขนาดเล็กมากด้วย malloc / free มาตรฐานไม่ได้มีประสิทธิภาพ หน่วยความจำทุกอันต้องการข้อมูลเพิ่มเติมและมีการกระจายตัวของขนาดที่เล็กกว่า

รายการฟรียังเป็นที่แรกที่ malloc ดูเมื่อต้องการหน่วยความจำอันใหม่ มันถูกสแกนก่อนที่จะเรียกใช้หน่วยความจำใหม่จากระบบปฏิบัติการ เมื่อพบก้อนที่ใหญ่กว่าหน่วยความจำที่ต้องการมันจะแบ่งออกเป็นสองส่วน หนึ่งจะถูกส่งกลับไปยังผู้โทรส่วนที่เหลือจะถูกส่งกลับไปยังรายการฟรี

มีการปรับให้เหมาะสมต่าง ๆ มากมายสำหรับพฤติกรรมมาตรฐานนี้ (เช่นสำหรับหน่วยความจำขนาดเล็ก) แต่เนื่องจาก malloc และฟรีต้องเป็นสากลดังนั้นพฤติกรรมมาตรฐานจึงเป็นทางเลือกเสมอเมื่อไม่มีทางเลือกอื่น นอกจากนี้ยังมีการเพิ่มประสิทธิภาพในการจัดการรายการอิสระ - ตัวอย่างเช่นการจัดเก็บชิ้นในรายการที่เรียงตามขนาด แต่การเพิ่มประสิทธิภาพทั้งหมดก็มีข้อ จำกัด เช่นกัน

ทำไมรหัสของคุณถึงพัง:

เหตุผลก็คือโดยการเขียนตัวอักษร 9 ตัว (อย่าลืมไบต์ว่างท้าย) ลงในพื้นที่ที่มีขนาด 4 ตัวอักษรคุณอาจจะเขียนทับข้อมูลการดูแลระบบที่เก็บไว้สำหรับหน่วยความจำอีกอันหนึ่งที่อยู่ด้านหลัง เนื่องจากข้อมูลนี้มักถูกเก็บไว้ที่ "ด้านหน้า" ของหน่วยความจำ) เมื่อว่างแล้วลองใส่ชิ้นของคุณลงในรายการฟรีมันสามารถสัมผัสข้อมูลการดูแลระบบนี้และสะดุดทับตัวชี้ที่เขียนทับ นี่จะทำให้ระบบขัดข้อง

นี่เป็นพฤติกรรมที่ค่อนข้างสง่างาม ฉันเคยเห็นสถานการณ์ที่ตัวชี้ที่หลบหนีอยู่ที่ไหนสักแห่งมีข้อมูลที่เขียนทับในรายการหน่วยความจำฟรีและระบบไม่ได้ผิดพลาดทันที แต่บางรูทีนย่อยในภายหลัง แม้แต่ในระบบที่มีความซับซ้อนปานกลางปัญหาดังกล่าวก็สามารถแก้ไขได้ยากจริงๆ! ในกรณีเดียวที่ฉันเกี่ยวข้องมันใช้เวลาเรา (กลุ่มนักพัฒนาขนาดใหญ่) มาหลายวันเพื่อหาสาเหตุของความผิดพลาด - เนื่องจากอยู่ในตำแหน่งที่แตกต่างไปจากที่ระบุโดยการถ่ายโอนข้อมูลหน่วยความจำ มันเหมือนระเบิดเวลา คุณรู้ไหมว่า "ฟรี" หรือ "malloc" ตัวถัดไปของคุณจะพัง แต่คุณไม่รู้ว่าทำไม!

ปัญหาเหล่านี้เป็นปัญหาของ C / C ++ ที่เลวร้ายที่สุดและสาเหตุหนึ่งที่ทำให้ตัวชี้สามารถเป็นปัญหาได้


63
Soooo หลายคนไม่ทราบว่าฟรี () อาจไม่คืนหน่วยความจำไปยังระบบปฏิบัติการมันโกรธ ขอบคุณที่ช่วยสอนพวกเขา
Artelius

อาร์เทลิอุส: ในทางตรงกันข้ามสิ่งใหม่ ๆ จะเกิดขึ้นเสมอหรือ
Guillaume07

3
@ Guillaume07 ฉันคิดว่าคุณหมายถึงการลบไม่ใช่เรื่องใหม่ ไม่มันไม่ได้ (จำเป็น) ลบและฟรีทำ (เกือบ) สิ่งเดียวกัน นี่คือรหัสที่แต่ละคนโทรใน MSVC2013: goo.gl/3O2Kyu
Yay295

1
ลบจะเรียก destructor เสมอ แต่หน่วยความจำเองอาจเข้าสู่รายการอิสระสำหรับการจัดสรรในภายหลัง ขึ้นอยู่กับการนำไปใช้งานมันอาจเป็นรายชื่อเดียวกับที่ malloc ใช้
เดวิดซี

1
@ Juergen แต่เมื่อฟรี () อ่านไบต์พิเศษซึ่งมีข้อมูลจำนวนหน่วยความจำที่จัดสรรจาก malloc จะได้รับ 4. จากนั้นความผิดพลาดที่เกิดขึ้นหรือจำนวนข้อมูลการดูแลระบบที่แตะได้ฟรีหรือไม่
พฤติกรรมที่ไม่ได้กำหนด

56

อย่างที่ aluser พูดในกระทู้ในฟอรัมนี้ :

กระบวนการของคุณมีขอบเขตของหน่วยความจำจากที่อยู่ x ไปยังที่อยู่ y เรียกว่าฮีป ข้อมูล malloc ทั้งหมดของคุณอาศัยอยู่ในพื้นที่นี้ malloc () เก็บโครงสร้างข้อมูลไว้สมมุติว่าเป็นรายการของพื้นที่ว่างทั้งหมดในกอง เมื่อคุณเรียก malloc มันจะตรวจสอบรายการของก้อนที่ใหญ่พอสำหรับคุณส่งคืนตัวชี้ไปที่และบันทึกความจริงที่ว่ามันไม่ปล่อยให้ว่างเปล่าอีกต่อไป เมื่อคุณโทรฟรี () ด้วยตัวชี้เดียวกัน free () จะค้นหาขนาดของก้อนที่มีขนาดใหญ่และเพิ่มกลับเข้าไปในรายการของชิ้นส่วนอิสระ () หากคุณเรียก malloc () และไม่พบชิ้นข้อมูลขนาดใหญ่พอใน heap จะใช้ brk () syscall เพื่อขยาย heap เช่นเพิ่มที่อยู่ y และทำให้ที่อยู่ทั้งหมดระหว่าง y เก่าและ y ใหม่เป็น เป็นหน่วยความจำที่ถูกต้อง brk () ต้องเป็น syscall;

malloc () ขึ้นอยู่กับระบบ / ผู้แปลจึงยากที่จะให้คำตอบเฉพาะ โดยทั่วไปแล้วมันจะคอยติดตามว่าหน่วยความจำนั้นถูกจัดสรรไว้อย่างไรและขึ้นอยู่กับว่ามันทำอย่างไรการโทรฟรีของคุณอาจล้มเหลว

malloc() and free() don't work the same way on every O/S.


1
นี่คือสาเหตุที่เรียกว่าพฤติกรรมที่ไม่ได้กำหนด การใช้งานอย่างหนึ่งอาจทำให้ปีศาจบินออกจากจมูกของคุณเมื่อคุณโทรฟรีหลังจากเขียนไม่ถูกต้อง คุณไม่เคยรู้.
Braden ที่ดีที่สุด

36

การติดตั้ง malloc / free หนึ่งครั้งจะทำสิ่งต่อไปนี้:

  1. รับบล็อกหน่วยความจำจากระบบปฏิบัติการผ่าน sbrk () (Unix call)
  2. สร้างส่วนหัวและท้ายกระดาษรอบ ๆ บล็อกของหน่วยความจำที่มีข้อมูลบางอย่างเช่นขนาดสิทธิ์และตำแหน่งที่บล็อกถัดไปและก่อนหน้าคือ
  3. เมื่อมีการโทรไปที่ malloc รายการจะถูกอ้างอิงซึ่งจะชี้ไปยังบล็อกที่มีขนาดที่เหมาะสม
  4. บล็อกนี้จะถูกส่งกลับและส่วนหัวและท้ายกระดาษจะได้รับการปรับปรุงตาม

25

การป้องกันหน่วยความจำมีหน้าย่อยและจะต้องมีการโต้ตอบเคอร์เนล

โค้ดตัวอย่างของคุณจะถามว่าทำไมโปรแกรมตัวอย่างจึงไม่ดักจับและคำตอบก็คือการป้องกันหน่วยความจำเป็นคุณสมบัติเคอร์เนลและใช้ได้กับทั้งหน้าเท่านั้นในขณะที่ตัวจัดสรรหน่วยความจำเป็นคุณสมบัติไลบรารีและจัดการ .. โดยไม่มีการบังคับ .. บล็อกขนาดใหญ่ซึ่งมักจะเล็กกว่าหน้ามาก

หน่วยความจำสามารถลบออกจากโปรแกรมของคุณในหน่วยของหน้าและแม้ที่ไม่น่าจะสังเกตได้

calloc (3) และ malloc (3) โต้ตอบกับเคอร์เนลเพื่อรับหน่วยความจำหากจำเป็น แต่การใช้งานฟรี (3) ส่วนใหญ่จะไม่ส่งคืนหน่วยความจำไปยังเคอร์เนล1พวกเขาเพียงแค่เพิ่มลงในรายการฟรีที่ calloc () และ malloc () จะปรึกษาในภายหลังเพื่อนำบล็อกที่นำออกใช้ซ้ำ

แม้ว่า free () ต้องการส่งคืนหน่วยความจำไปยังระบบ แต่ก็ต้องการหน้าหน่วยความจำต่อเนื่องอย่างน้อยหนึ่งหน้าเพื่อให้เคอร์เนลปกป้องพื้นที่จริงดังนั้นการปล่อยบล็อกขนาดเล็กจะนำไปสู่การเปลี่ยนแปลงการป้องกันหากเป็นสุดท้ายบล็อกเล็ก ๆ ในหน้า

บล็อกของคุณอยู่ตรงนั้นนั่งอยู่บนรายชื่อฟรี คุณสามารถเข้าถึงได้ตลอดเวลาและหน่วยความจำใกล้เคียงราวกับว่ามันยังถูกจัดสรรอยู่ C คอมไพล์ตรงไปยังรหัสเครื่องและไม่มีการจัดการดีบั๊กพิเศษไม่มีการตรวจสอบสติในการโหลดและร้านค้า ตอนนี้ถ้าคุณลองและเข้าถึงบล็อกฟรีพฤติกรรมนั้นไม่ได้ถูกกำหนดโดยมาตรฐานเพื่อไม่ให้มีความต้องการที่ไม่สมเหตุสมผลกับผู้ใช้งานไลบรารี หากคุณลองและเข้าถึงหน่วยความจำที่ว่างหรือ meory นอกบล็อกที่จัดสรรมีหลายสิ่งที่อาจผิดพลาดได้:

  • บางครั้งตัวจัดสรรจัดสรรหน่วยความจำแยกต่างหากบางครั้งพวกเขาใช้ส่วนหัวที่จัดสรรก่อนหรือหลัง ("ส่วนท้าย" ฉันเดา) บล็อกของคุณ แต่พวกเขาอาจต้องการใช้หน่วยความจำภายในบล็อกเพื่อจุดประสงค์ในการเก็บรายการฟรี เชื่อมโยงเข้าด้วยกัน ถ้าเป็นเช่นนั้นการอ่านบล็อกของคุณก็โอเค แต่เนื้อหาในบล็อกอาจเปลี่ยนไปและการเขียนลงในบล็อกน่าจะทำให้ตัวปันส่วนทำงานผิดหรือผิดพลาด
  • โดยปกติบล็อกของคุณอาจถูกจัดสรรในอนาคตและจากนั้นมีแนวโน้มที่จะถูกเขียนทับโดยโค้ดหรือรูทีนไลบรารีของคุณหรือด้วยเลขศูนย์โดย calloc ()
  • หากบล็อกถูกจัดสรรใหม่อาจมีการเปลี่ยนแปลงขนาดของมันซึ่งในกรณีนี้จะมีการเขียนลิงก์หรือการเริ่มต้นเพิ่มเติมในที่ต่าง ๆ
  • เห็นได้ชัดว่าคุณอาจอ้างอิงถึงช่วงที่คุณข้ามขอบเขตของเซ็กเมนต์เคอร์เนลรู้จักโปรแกรมของคุณและในกรณีนี้คุณจะดัก

ทฤษฎีการปฏิบัติงาน

ดังนั้นการย้อนกลับจากตัวอย่างของคุณไปจนถึงทฤษฎีโดยรวม malloc (3) ได้รับหน่วยความจำจากเคอร์เนลเมื่อมันต้องการและโดยปกติจะอยู่ในหน่วยของหน้า หน้าเหล่านี้ถูกแบ่งออกหรือรวมเข้าด้วยกันตามที่โปรแกรมต้องการ Malloc และให้ความร่วมมือในการรักษาไดเรกทอรี พวกมันรวมตัวกันบล็อกฟรีที่อยู่ติดกันเมื่อเป็นไปได้เพื่อให้สามารถให้บล็อกขนาดใหญ่ ไดเรกทอรีอาจหรือไม่เกี่ยวข้องกับการใช้หน่วยความจำในบล็อกอิสระเพื่อสร้างรายการเชื่อมโยง (ทางเลือกคือหน่วยความจำที่ใช้ร่วมกันอีกเล็กน้อยและเป็นมิตรกับเพจและเกี่ยวข้องกับการจัดสรรหน่วยความจำโดยเฉพาะสำหรับไดเรกทอรี) Malloc และฟรีมีความสามารถในการบังคับใช้การเข้าถึงบล็อกแต่ละบล็อกแม้ในกรณีที่รหัสพิเศษ โปรแกรม.


1. ความจริงที่ว่าการใช้งานฟรีจำนวนน้อย () ของความพยายามในการส่งคืนหน่วยความจำไปยังระบบนั้นไม่จำเป็นว่าจะเกิดจากผู้ใช้งานที่หย่อนลง การโต้ตอบกับเคอร์เนลนั้นช้ากว่าการใช้งานไลบรารี่โค้ดเพียงเล็กน้อยและข้อดีก็จะเล็ก โปรแกรมส่วนใหญ่มีสถานะหน่วยความจำคงที่หรือเพิ่มขึ้นดังนั้นเวลาที่ใช้ในการวิเคราะห์ฮีปที่ค้นหาหน่วยความจำที่ส่งคืนได้จะสูญเปล่าไปโดยสิ้นเชิง เหตุผลอื่น ๆ รวมถึงข้อเท็จจริงที่ว่าการกระจายตัวของภายในทำให้บล็อกที่อยู่ในแนวหน้าไม่น่าจะมีอยู่และเป็นไปได้ว่าการส่งคืนบล็อกจะทำให้บล็อกแตกเป็นส่วน ๆ ในที่สุดโปรแกรมไม่กี่โปรแกรมที่ส่งคืนหน่วยความจำจำนวนมากมีแนวโน้มที่จะเลี่ยงผ่าน malloc () และเพียงจัดสรรและเพิ่มเพจให้ว่าง


คำตอบที่ดี. อยากจะแนะนำกระดาษ: การจัดสรรพื้นที่เก็บข้อมูลแบบไดนามิก: การสำรวจและการตรวจสอบที่สำคัญโดยวิลสันและคณะสำหรับการตรวจสอบเชิงลึกเกี่ยวกับกลไกภายในเช่นเขตข้อมูลส่วนหัวและรายการฟรีที่ใช้โดยผู้จัดสรร
Goaler444

23

ในทางทฤษฎี malloc ได้รับหน่วยความจำจากระบบปฏิบัติการสำหรับแอปพลิเคชันนี้ อย่างไรก็ตามเนื่องจากคุณอาจต้องการเพียง 4 ไบต์และระบบปฏิบัติการจำเป็นต้องทำงานในหน้าเว็บ (มักจะเป็น 4k) malloc จึงทำมากกว่านั้น ใช้หน้าและใส่ข้อมูลของตัวเองในนั้นเพื่อให้สามารถติดตามสิ่งที่คุณได้จัดสรรและเป็นอิสระจากหน้านั้น

เมื่อคุณจัดสรร 4 ไบต์ตัวอย่าง malloc จะให้ตัวชี้ถึง 4 ไบต์ สิ่งที่คุณอาจไม่ทราบก็คือหน่วยความจำ 8-12 ไบต์ก่อน malloc 4 ไบต์ของคุณถูกใช้เพื่อสร้างสายโซ่ของหน่วยความจำทั้งหมดที่คุณจัดสรรไว้ เมื่อคุณโทรฟรีจะใช้ตัวชี้ของคุณสำรองข้อมูลไปยังที่ที่ข้อมูลอยู่และทำงานกับสิ่งนั้น

เมื่อคุณเพิ่มหน่วยความจำ malloc จะบล็อกหน่วยความจำนั้นออกจากสายโซ่ ... และอาจหรือไม่อาจส่งคืนหน่วยความจำนั้นไปยังระบบปฏิบัติการ ถ้าเป็นเช่นนั้นการเข้าถึงหน่วยความจำนั้นอาจจะล้มเหลวเนื่องจากระบบปฏิบัติการจะลบสิทธิ์ของคุณในการเข้าถึงตำแหน่งนั้น หาก malloc เก็บหน่วยความจำ (เพราะมีสิ่งอื่น ๆ ที่จัดสรรไว้ในหน้านั้นหรือเพื่อการปรับให้เหมาะสมที่สุด) การเข้าถึงจะเกิดขึ้นได้ มันยังคงผิดปกติ แต่อาจใช้งานได้

การปฏิเสธความรับผิด: สิ่งที่ฉันอธิบายคือการใช้งานทั่วไปของ malloc แต่ไม่เคยมีความเป็นไปได้เพียงอย่างเดียว


12

สาย strcpy ของคุณพยายามที่จะเก็บ 9 ไบต์ไม่ใช่ 8 เนื่องจากจุดสิ้นสุดของ NUL มันเรียกพฤติกรรมที่ไม่ได้กำหนด

โทรฟรีหรืออาจจะผิดพลาด หน่วยความจำ "หลังจาก" 4 ไบต์ของการจัดสรรของคุณอาจถูกใช้เพื่อสิ่งอื่นโดยการใช้ C หรือ C ++ ของคุณ หากมันถูกใช้เพื่อสิ่งอื่นแล้วการเขียนลวก ๆ ให้ทั่วก็จะทำให้ "อย่างอื่น" ผิดไป แต่ถ้ามันไม่ได้ใช้เพื่ออะไรอย่างอื่นคุณก็สามารถหนีไปได้ "การไปกับมัน" อาจฟังดูดี แต่จริงๆแล้วมันแย่เพราะมันหมายความว่าโค้ดของคุณจะปรากฏว่าทำงานได้ดี แต่ในการทำงานในอนาคตคุณอาจไม่ได้ไปกับมัน

ด้วยตัวจัดสรรหน่วยความจำแบบดีบักคุณอาจพบว่ามีการเขียนค่าความปลอดภัยพิเศษที่นั่นและตรวจสอบค่าและความตื่นตระหนกนั้นฟรีหากไม่พบ

มิฉะนั้นคุณอาจพบว่า 5 ไบต์ถัดไปมีส่วนหนึ่งของโหนดลิงก์ที่เป็นของบล็อกหน่วยความจำอื่นที่ยังไม่ได้รับการจัดสรร การเลิกบล็อกของคุณอาจเกี่ยวข้องกับการเพิ่มบล็อกลงในรายการบล็อกที่มีอยู่และเนื่องจากคุณเขียนในโหนดรายการการดำเนินการนั้นอาจยกเลิกการใช้ตัวชี้ที่มีค่าที่ไม่ถูกต้องทำให้เกิดความผิดพลาด

ทุกอย่างขึ้นอยู่กับการจัดสรรหน่วยความจำ - การใช้งานที่แตกต่างกันใช้กลไกที่แตกต่างกัน


12

วิธีที่ malloc () และ free () ทำงานขึ้นกับไลบรารีรันไทม์ที่ใช้ โดยทั่วไป malloc () จะจัดสรรฮีป (บล็อกของหน่วยความจำ) จากระบบปฏิบัติการ แต่ละคำขอให้ malloc () จากนั้นจัดสรรชิ้นเล็ก ๆ ของหน่วยความจำนี้จะส่งกลับตัวชี้ไปยังผู้โทร รูทีนการจัดสรรหน่วยความจำจะต้องเก็บข้อมูลเพิ่มเติมบางอย่างเกี่ยวกับบล็อกหน่วยความจำที่จัดสรรเพื่อให้สามารถติดตามการใช้งานและหน่วยความจำว่างบนฮีป ข้อมูลนี้มักจะถูกเก็บไว้ในไม่กี่ไบต์ก่อนที่ตัวชี้จะถูกส่งกลับโดย malloc () และสามารถเป็นรายการที่เชื่อมโยงของบล็อกหน่วยความจำ

โดยการเขียนบล็อกหน่วยความจำที่จัดสรรโดย malloc () ที่ผ่านมาคุณจะทำลายข้อมูลการเก็บหนังสือบางส่วนของบล็อกถัดไปซึ่งอาจเป็นบล็อกหน่วยความจำที่ไม่ได้ใช้ที่เหลืออยู่

ที่เดียวที่โปรแกรมของคุณอาจล้มเหลวคือเมื่อคัดลอกอักขระจำนวนมากเกินไปลงในบัฟเฟอร์ หากอักขระพิเศษอยู่นอกกองคุณอาจได้รับการละเมิดการเข้าถึงเนื่องจากคุณกำลังพยายามเขียนไปยังหน่วยความจำที่ไม่มีอยู่


6

สิ่งนี้ไม่มีอะไรเกี่ยวข้องกับ malloc และฟรีโดยเฉพาะ โปรแกรมของคุณแสดงพฤติกรรมที่ไม่ได้กำหนดหลังจากที่คุณคัดลอกสตริง - มันอาจผิดพลาดที่จุดนั้นหรือ ณ จุดใด ๆ หลังจากนั้น สิ่งนี้จะเป็นจริงแม้ว่าคุณจะไม่เคยใช้ malloc และฟรีและจัดสรรอาร์เรย์ถ่านบนสแต็กหรือสแตติก


5

malloc และ free ขึ้นอยู่กับการใช้งาน การนำไปใช้โดยทั่วไปเกี่ยวข้องกับการแบ่งพาร์ติชันหน่วยความจำที่มีอยู่ใน "รายการว่าง" - รายการที่เชื่อมโยงของบล็อกหน่วยความจำที่มีอยู่ การใช้งานหลายคนเทียมแบ่งเป็นวัตถุขนาดเล็กและใหญ่ บล็อกฟรีเริ่มต้นด้วยข้อมูลเกี่ยวกับบล็อกหน่วยความจำขนาดใหญ่และตำแหน่งถัดไปเป็นต้น

เมื่อคุณ malloc บล็อกจะถูกดึงจากรายการฟรี เมื่อคุณว่างบล็อกจะถูกใส่กลับเข้าไปในรายการฟรี โอกาสที่จะเกิดขึ้นเมื่อคุณเขียนทับปลายตัวชี้ของคุณคุณกำลังเขียนบนส่วนหัวของบล็อกในรายการอิสระ เมื่อคุณเพิ่มหน่วยความจำของคุณฟรี () พยายามดูบล็อกถัดไปและอาจจบลงด้วยการกดปุ่มตัวชี้ที่ทำให้เกิดข้อผิดพลาดของบัส


4

มันขึ้นอยู่กับการใช้งานตัวจัดสรรหน่วยความจำและระบบปฏิบัติการ

ภายใต้หน้าต่างเช่นกระบวนการสามารถขอหน้าหรือ RAM มากกว่า จากนั้นระบบปฏิบัติการจะกำหนดหน้าเหล่านั้นให้กับกระบวนการ อย่างไรก็ตามนี่ไม่ใช่หน่วยความจำที่จัดสรรให้แอปพลิเคชันของคุณ ตัวจัดสรรหน่วยความจำ CRT จะทำเครื่องหมายหน่วยความจำว่าเป็นบล็อก "พร้อม" ที่ต่อเนื่องกัน ตัวจัดสรรหน่วยความจำ CRT จะเรียกใช้ผ่านรายการบล็อกว่างและค้นหาบล็อกที่เล็กที่สุดเท่าที่จะเป็นไปได้ จากนั้นจะใช้บล็อกนั้นมากเท่าที่ต้องการและเพิ่มลงในรายการ "จัดสรร" แนบกับส่วนหัวของการจัดสรรหน่วยความจำจริงจะเป็นส่วนหัว ส่วนหัวนี้จะมีข้อมูลที่แตกต่างกันเล็กน้อย (ตัวอย่างเช่นอาจมีบล็อกที่จัดสรรถัดไปและก่อนหน้าเพื่อสร้างรายการที่เชื่อมโยงซึ่งส่วนใหญ่จะมีขนาดของการจัดสรร)

ฟรีจะลบส่วนหัวและเพิ่มกลับไปยังรายการหน่วยความจำฟรี หากเป็นบล็อกขนาดใหญ่ที่มีบล็อกว่างโดยรอบเหล่านี้จะถูกรวมเข้าด้วยกันเพื่อให้บล็อกใหญ่ขึ้น หากหน้าทั้งหมดว่างให้ผู้จัดสรรเป็นไปได้มากที่สุดให้ส่งคืนหน้าไปยังระบบปฏิบัติการ

มันไม่ใช่ปัญหาง่าย ส่วนตัวจัดสรรระบบปฏิบัติการไม่อยู่ในการควบคุมของคุณอย่างสมบูรณ์ ฉันขอแนะนำให้คุณอ่านบางอย่างเช่น Doug Lea's Malloc (DLMalloc) เพื่อทำความเข้าใจว่าตัวจัดสรรจัดสรรแบบรวดเร็วทำงานอย่างไร

แก้ไข: ความผิดพลาดของคุณจะเกิดจากข้อเท็จจริงที่ว่าโดยการเขียนใหญ่กว่าการจัดสรรที่คุณเขียนทับส่วนหัวของหน่วยความจำต่อไป วิธีนี้เมื่อมันปลดปล่อยมันจะสับสนมากกับสิ่งที่ว่ามันว่างเปล่าและวิธีการรวมเข้ากับบล็อกต่อไปนี้ สิ่งนี้อาจไม่ทำให้เกิดความผิดพลาดทันทีเมื่อใช้ฟรี มันอาจทำให้เกิดความผิดพลาดในภายหลัง โดยทั่วไปหลีกเลี่ยงการเขียนทับหน่วยความจำ!


3

โปรแกรมของคุณขัดข้องเนื่องจากใช้หน่วยความจำที่ไม่ได้เป็นของคุณ มันอาจถูกใช้โดยคนอื่นหรือไม่ - ถ้าคุณโชคดีคุณผิดพลาดหากไม่มีปัญหาอาจซ่อนอยู่เป็นเวลานานและกลับมากัดคุณในภายหลัง

เท่าที่ malloc / การใช้งานฟรีไป - หนังสือทั้งหมดจะทุ่มเทให้กับหัวข้อ โดยทั่วไปตัวจัดสรรจะได้รับหน่วยความจำที่ใหญ่กว่าจากระบบปฏิบัติการและจัดการให้คุณ ปัญหาบางอย่างที่ผู้จัดสรรต้องแก้ไขคือ:

  • วิธีรับหน่วยความจำใหม่
  • วิธีจัดเก็บ - (รายการหรือโครงสร้างอื่น ๆ หลายรายการสำหรับหน่วยความจำที่มีขนาดแตกต่างกันเป็นต้น)
  • จะทำอย่างไรถ้าผู้ใช้ร้องขอหน่วยความจำมากกว่าที่มีอยู่ในปัจจุบัน (ขอหน่วยความจำเพิ่มเติมจากระบบปฏิบัติการ, เข้าร่วมบางส่วนของบล็อกที่มีอยู่, วิธีการเข้าร่วมพวกเขาอย่างแน่นอน, ... )
  • จะทำอย่างไรเมื่อผู้ใช้เพิ่มหน่วยความจำ
  • ดีบักตัวจัดสรรอาจให้ก้อนที่ใหญ่กว่าที่คุณร้องขอและเติมรูปแบบไบต์บางอย่างเมื่อคุณเพิ่มหน่วยความจำตัวจัดสรรสามารถตรวจสอบว่าเขียนนอกบล็อก (ซึ่งอาจเกิดขึ้นในกรณีของคุณ) ...

2

มันยากที่จะพูดเพราะพฤติกรรมที่แท้จริงแตกต่างกันระหว่างคอมไพเลอร์ / รันไทม์ที่ต่างกัน แม้แต่การสร้าง debug / release ก็ยังมีพฤติกรรมที่แตกต่างกัน Debug builds ของ VS2005 จะแทรกเครื่องหมายระหว่างการจัดสรรเพื่อตรวจสอบความเสียหายของหน่วยความจำดังนั้นแทนที่จะเกิดข้อผิดพลาดจะยืนยันได้ฟรี ()


1

สิ่งสำคัญคือต้องตระหนักว่าการย้ายตัวชี้ตัวแบ่งโปรแกรมไปรอบ ๆ ด้วยbrkและsbrkไม่ได้จัดสรรหน่วยความจำจริง ๆเพียงตั้งค่าพื้นที่ที่อยู่ ตัวอย่างเช่นบน Linux หน่วยความจำจะถูก "สำรอง" โดยเพจฟิสิคัลจริงเมื่อเข้าถึงช่วงที่อยู่ซึ่งจะส่งผลให้เกิดความผิดพลาดของหน้าและในที่สุดจะนำไปสู่การเรียกเคอร์เนลลงในตัวจัดสรรหน้า

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.