เมื่อคุณออกจากแอปพลิเคชัน C หน่วยความจำ malloc-ed จะถูกปลดปล่อยโดยอัตโนมัติหรือไม่?


94

สมมติว่าฉันมีรหัส C ต่อไปนี้:

int main () {
  int *p = malloc(10 * sizeof *p);
  *p = 42;
  return 0;  //Exiting without freeing the allocated memory
}

เมื่อฉันรวบรวมและดำเนินการโปรแกรม C นั้นเช่นหลังจากจัดสรรพื้นที่ในหน่วยความจำแล้วหน่วยความจำที่ฉันจัดสรรจะยังคงได้รับการจัดสรร (กล่าวคือใช้พื้นที่ว่าง) หลังจากที่ฉันออกจากแอปพลิเคชันและกระบวนการสิ้นสุดลงหรือไม่


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

คำตอบ:


114

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

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


16
ครั้งหนึ่งฉันเคยพบ win98 บนแพลตฟอร์มแบบฝังและจากประสบการณ์นั้นฉันสามารถพูดได้ว่ามันไม่ได้ทำให้หน่วยความจำว่างเมื่อโปรแกรมปิด
San Jacinto

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

5
1: สิ่งที่สำคัญที่สุดที่จะต้องพิจารณาคือการจัดการหน่วยความจำที่เป็น Yacoby ค่อนข้างถูกต้องฯ : "คุณสมบัติของระบบปฏิบัติการที่เป็น" ภาษาโปรแกรมไม่ได้กำหนดสิ่งที่เกิดขึ้นก่อนหรือหลังการเรียกใช้โปรแกรมเว้นแต่ฉันจะเข้าใจผิด
D.Shawley

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

6
ใครก็ตามที่เสนอความจำรั่วใน SO ควรถูกปลดออกจากชื่อเสียงและตราสัญลักษณ์ทั้งหมด
Ul ภายนอก

53

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

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

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

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

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


11

ขอโทษที่โพสต์นานมากหลังจากโพสต์ล่าสุดในกระทู้นี้

อีกหนึ่งจุด ไม่ใช่ทุกโปรแกรมที่ทำให้ออกอย่างสง่างาม การขัดข้องและ ctrl-C เป็นต้นจะทำให้โปรแกรมออกจากระบบโดยไม่สามารถควบคุมได้ หากระบบปฏิบัติการของคุณไม่ทำให้ฮีปของคุณเป็นอิสระให้ล้างสแต็กลบตัวแปรคงที่ ฯลฯ ในที่สุดคุณจะทำให้ระบบของคุณพังจากการรั่วไหลของหน่วยความจำหรือแย่ลง

ที่น่าสนใจนอกเหนือจากนี้ล่ม / หยุดทำงานใน Ubuntu และฉันสงสัยว่าระบบปฏิบัติการสมัยใหม่อื่น ๆ ทั้งหมดมีปัญหากับทรัพยากรที่ "จัดการ" ซ็อกเก็ตไฟล์อุปกรณ์ ฯลฯ สามารถ "เปิด" ได้เมื่อโปรแกรมสิ้นสุด / ล่ม นอกจากนี้วิธีปฏิบัติที่ดีในการปิดสิ่งใด ๆ ด้วย "ที่จับ" หรือ "ตัวอธิบาย" ซึ่งเป็นส่วนหนึ่งของการทำความสะอาดของคุณก่อนออกอย่างสง่า

ฉันกำลังพัฒนาโปรแกรมที่ใช้ซ็อกเก็ตอย่างหนัก เมื่อฉันติดอยู่ในแฮงค์ฉันต้อง ctrl-c จากมันดังนั้นการควั่นซ็อกเก็ตของฉัน ฉันเพิ่ม std :: vector เพื่อรวบรวมรายการซ็อกเก็ตที่เปิดทั้งหมดและตัวจัดการ sigaction ที่จับ sigint และ sigterm ตัวจัดการจะเดินรายการและปิดซ็อกเก็ต ฉันวางแผนที่จะสร้างขั้นตอนการล้างข้อมูลที่คล้ายกันเพื่อใช้ก่อนที่จะโยนซึ่งจะนำไปสู่การยุติก่อนกำหนด

ใครสนใจที่จะแสดงความคิดเห็นเกี่ยวกับการออกแบบนี้?


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

8
Stackoverflow ไม่ใช่ฟอรัม มีอะไรผิดปกติกับการตอบคำถามเก่า meta.stackexchange.com/questions/20524/reviving-old-questions
mk12

6

สิ่งที่เกิดขึ้นที่นี่ ( ในระบบปฏิบัติการสมัยใหม่ ) คือโปรแกรมของคุณทำงานภายใน "กระบวนการ" ของตัวเอง นี่คือเอนทิตีระบบปฏิบัติการที่มีพื้นที่แอดเดรสของตัวเองตัวอธิบายไฟล์ ฯลฯ การmallocโทรของคุณกำลังจัดสรรหน่วยความจำจาก "ฮีป" หรือเพจหน่วยความจำที่ไม่ได้ปันส่วนที่กำหนดให้กับกระบวนการของคุณ

เมื่อโปรแกรมของคุณสิ้นสุดลงดังตัวอย่างนี้ทรัพยากรทั้งหมดที่กำหนดให้กับกระบวนการของคุณจะถูกนำกลับมาใช้ใหม่ / ฉีกทิ้งโดยระบบปฏิบัติการ ในกรณีของหน่วยความจำเพจหน่วยความจำทั้งหมดที่กำหนดให้คุณจะถูกทำเครื่องหมายว่า "ว่าง" และนำไปรีไซเคิลเพื่อใช้ในกระบวนการอื่น ๆ Pages เป็นแนวคิดระดับล่างกว่าที่ malloc จัดการด้วยเหตุนี้ความเฉพาะเจาะจงของ malloc / free จึงถูกชะล้างออกไปเมื่อทุกสิ่งได้รับการทำความสะอาด

เป็นคุณธรรมที่เทียบเท่าเมื่อคุณใช้แล็ปท็อปของคุณเสร็จแล้วและต้องการมอบให้เพื่อนคุณไม่ต้องกังวลกับการลบทีละไฟล์ คุณเพียงแค่ฟอร์แมตฮาร์ดไดรฟ์

สิ่งที่กล่าวมาทั้งหมดนี้เนื่องจากผู้ตอบรายอื่นทั้งหมดสังเกตว่าการอาศัยสิ่งนี้ไม่ใช่แนวทางปฏิบัติที่ดี:

  1. คุณควรเขียนโปรแกรมเพื่อดูแลทรัพยากรอยู่เสมอและในภาษา C นั้นหมายถึงหน่วยความจำเช่นกัน คุณอาจลงเอยด้วยการฝังโค้ดของคุณในไลบรารีหรืออาจใช้งานได้นานกว่าที่คุณคาดไว้
  2. ระบบปฏิบัติการบางระบบ (รุ่นเก่าและระบบฝังตัวที่ทันสมัยบางระบบ) อาจไม่รักษาขอบเขตของกระบวนการที่ยากเช่นนี้และการจัดสรรของคุณอาจส่งผลกระทบต่อพื้นที่ที่อยู่ของผู้อื่น

4

ใช่. ระบบปฏิบัติการล้างทรัพยากร ดี ... NetWare เวอร์ชันเก่าไม่มี

แก้ไข: ดังที่ San Jacinto ชี้ให้เห็นว่ามีระบบ (นอกเหนือจาก NetWare) ที่ไม่ทำเช่นนั้น แม้จะอยู่ในโปรแกรมแบบทิ้งฉันก็พยายามสร้างนิสัยในการปลดปล่อยทรัพยากรทั้งหมดเพียงเพื่อให้เป็นนิสัย


3
ฉันไม่ได้ลงคะแนน แต่นี่เป็นโพสต์ที่ค่อนข้างอันตรายสำหรับลูกหลาน DOS ยังคงใช้กับแพลตฟอร์มฝังตัวจำนวนมากและฉันสงสัยอย่างมากว่าจะล้างหน่วยความจำให้คุณ ลักษณะทั่วไปที่กวาดไม่ถูกต้อง
San Jacinto

@ San Jacinto: นั่นเป็นจุดที่ดี นั่นคือเหตุผลที่ฉันทำการอ้างอิง NetWare แต่อาจใช้คำชี้แจงได้ ฉันจะแก้ไขมันเล็กน้อย
Mark Wilkins

3
@San DOS ไม่ใช่ระบบปฏิบัติการแบบมัลติทาสก์ - เมื่อโปรแกรม DOS (ไม่รวม TSR) สิ้นสุดลงหน่วยความจำทั้งหมดจะพร้อมใช้งานสำหรับโปรแกรมถัดไปที่จะโหลด

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

2

ใช่ระบบปฏิบัติการจะปล่อยหน่วยความจำทั้งหมดเมื่อกระบวนการสิ้นสุดลง


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

7
Wikipedia ไม่ใช่คู่มือสำหรับทุกระบบปฏิบัติการที่มีอยู่ ระบบปฏิบัติการที่ทันสมัยส่วนใหญ่ จะเรียกคืนหน่วยความจำ แต่ไม่ใช่ทั้งหมด (และโดยเฉพาะไม่ใช่รุ่นเก่าทั้งหมด) ทำ เพิ่มไปที่สามารถสัญญาว่าสิ่งที่ซีจะทำอะไรกับหน่วยความจำ; จากการออกแบบ C ไม่รับประกันอะไรมากเกี่ยวกับพฤติกรรมภายนอกตัว C หากแอปตายโดยไม่คาดคิดคำสัญญาใด ๆ ที่ไลบรารีรันไทม์ทำไว้จะเป็นโมฆะเนื่องจากไม่มีชีวิตที่จะอยู่กับพวกเขา malloc
cHao

2

ขึ้นอยู่กับว่าระบบปฏิบัติการมักจะล้างข้อมูลให้คุณ แต่ถ้าคุณกำลังทำงานกับซอฟต์แวร์ฝังตัวเช่นซอฟต์แวร์นั้นอาจไม่ถูกปล่อยออกมา

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


0

ขึ้นอยู่กับระบบปฏิบัติการจริง ๆ แต่สำหรับระบบปฏิบัติการทั้งหมดที่คุณเคยพบการจัดสรรหน่วยความจำจะหายไปเมื่อกระบวนการออก


0

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

ว่าอยู่ที่ไหนหรือว่าฉันพบว่าใน W98 คำถามที่แท้จริงคือ 'เมื่อไหร่' (ฉันไม่เห็นโพสต์ที่เน้นเรื่องนี้) โปรแกรมเทมเพลตขนาดเล็ก (สำหรับการป้อนข้อมูล MIDI SysEx โดยใช้ช่องว่าง malloc ต่างๆ) จะทำให้หน่วยความจำว่างในบิต WM_DESTROY ของ WndProc แต่เมื่อฉันย้ายสิ่งนี้ไปยังโปรแกรมที่ใหญ่กว่ามันจะล้มเหลวเมื่อออก ฉันคิดว่านี่หมายความว่าฉันกำลังพยายามปลดปล่อยสิ่งที่ระบบปฏิบัติการได้ปลดปล่อยไปแล้วในระหว่างการล้างข้อมูลขนาดใหญ่ ถ้าฉันทำบน WM_CLOSE แล้วเรียกว่า DestroyWindow () ทุกอย่างทำงานได้ดีออกทันที

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

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

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