เหตุใด "อิสระ" ใน C จึงไม่ใช้จำนวนไบต์ที่จะทำให้เป็นอิสระ


84

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

แต่ฉันอยากรู้ว่าทำไมถึงfreeทำแบบนี้ตั้งแต่แรก ในฐานะที่เป็นภาษาระดับต่ำฉันคิดว่ามันเป็นเรื่องที่สมเหตุสมผลอย่างยิ่งที่จะขอให้โปรแกรมเมอร์ C ติดตามไม่เพียง แต่หน่วยความจำที่ได้รับการจัดสรร แต่เท่าไหร่ (อันที่จริงฉันมักจะพบว่าฉันติดตามจำนวนไบต์ malloced อยู่ดี) นอกจากนี้ยังเกิดขึ้นกับฉันที่การให้จำนวนไบต์อย่างชัดเจนfreeอาจอนุญาตให้มีการเพิ่มประสิทธิภาพประสิทธิภาพบางอย่างเช่นตัวจัดสรรที่มีพูลแยกต่างหากสำหรับขนาดการจัดสรรที่แตกต่างกันจะสามารถกำหนดพูลที่จะว่างเพียงแค่ดูที่อาร์กิวเมนต์อินพุตและ จะมีพื้นที่เหนือศีรษะโดยรวมน้อยลง

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

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


18
เนื่องจากมันเป็นความเจ็บปวดในการติดตามการจัดสรรด้วยตัวเองและมันจะทำให้โค้ดซับซ้อนมากขึ้นหากคุณต้องติดตามขนาดเพิ่มเติม
Jens Gustedt

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

15
@BoBTFish: นี่คือC ที่เรากำลังพูดถึงไม่ใช่ Python หรือแม้แต่ C ++ ผู้ใช้ต้องทำ $ h! 1 ตันที่เขาไม่ต้องทำ นั่นไม่ใช่เหตุผล
user541686

4
K&R ไม่มีอะไรจะพูดเกี่ยวกับเรื่องนี้เช่นกัน เราสามารถคาดการณ์ทั้งหมดที่เราต้องการ แต่ผมคิดว่าเหตุผลที่เดิมอาจจะหายไปในประวัติศาสตร์
BoBTFish

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

คำตอบ:


98

อาร์กิวเมนต์เดียวfree(void *)(แนะนำใน Unix V7) มีข้อได้เปรียบที่สำคัญอีกประการหนึ่งจากสองอาร์กิวเมนต์ก่อนหน้านี้mfree(void *, size_t)ซึ่งฉันไม่เคยเห็นที่นี่: หนึ่งอาร์กิวเมนต์freeช่วยลดความซับซ้อนของAPI อื่น ๆที่ทำงานกับหน่วยความจำฮีปได้อย่างมาก ตัวอย่างเช่นหากfreeต้องการขนาดของบล็อกหน่วยความจำก็strdupจะต้องคืนค่าสองค่า (ตัวชี้ + ขนาด) แทนที่จะเป็นค่าเดียว (ตัวชี้) และ C ทำให้การส่งคืนหลายค่ายุ่งยากกว่าการส่งคืนค่าเดียว แทนการchar *strdup(char *)ที่เราจะต้องเขียนหรืออื่น ๆchar *strdup(char *, size_t *) struct CharPWithSize { char *val; size_t size}; CharPWithSize strdup(char *)(ปัจจุบันตัวเลือกที่สองนั้นดูน่าดึงดูดทีเดียวเพราะเราทราบดีว่าสตริงที่ยุติด้วย NUL นั้นเป็น"จุดบกพร่องในการออกแบบที่หายนะที่สุดในประวัติศาสตร์ของการคำนวณ"แต่นั่นเป็นการพูดที่มองย้อนกลับไป ย้อนกลับไปในทศวรรษที่ 70 ความสามารถของ C ในการจัดการกับสตริงอย่างง่ายchar *ๆ ถือเป็นข้อได้เปรียบที่กำหนดเหนือคู่แข่งเช่น Pascal และ Algol ) นอกจากนี้ไม่เพียงแค่strdupประสบปัญหานี้เท่านั้น แต่ยังส่งผลกระทบต่อทุกระบบหรือผู้ใช้กำหนด ฟังก์ชันที่จัดสรรหน่วยความจำฮีป

นักออกแบบ Unix ยุคแรก ๆ เป็นคนที่ฉลาดมากและมีหลายสาเหตุที่freeดีกว่าmfreeโดยพื้นฐานแล้วฉันคิดว่าคำตอบสำหรับคำถามคือพวกเขาสังเกตเห็นสิ่งนี้และออกแบบระบบของพวกเขาตามนั้น ฉันสงสัยว่าคุณจะพบบันทึกโดยตรงเกี่ยวกับสิ่งที่เกิดขึ้นในหัวของพวกเขาในขณะที่พวกเขาตัดสินใจ แต่เราสามารถจินตนาการ

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

และยิ่งคุณเขียนโค้ดโดยใช้ฟังก์ชันใหม่เหล่านี้มากเท่าไหร่ก็ยิ่งดูน่ากลัวมากขึ้นเท่านั้น ไม่เพียง แต่ทำให้โค้ดของคุณเขียนง่ายขึ้นเท่านั้น แต่ยังทำให้โค้ดของคุณเร็วขึ้น - สองสิ่งที่มักไม่ได้อยู่ด้วยกัน! ก่อนที่คุณจะส่งผ่านสิ่งเหล่านี้size_tไปทั่วทุกที่ซึ่งเพิ่มค่าใช้จ่ายของ CPU สำหรับการคัดลอกและหมายความว่าคุณต้องทำรีจิสเตอร์บ่อยขึ้น (โดยเฉพาะสำหรับอาร์กิวเมนต์ฟังก์ชันพิเศษ) และหน่วยความจำที่สูญเปล่า (เนื่องจากการเรียกฟังก์ชันซ้อนกันมักจะส่งผล ในหลายสำเนาของsize_tการจัดเก็บในเฟรมสแตกต่างกัน) ในระบบใหม่ของคุณคุณยังต้องใช้หน่วยความจำในการจัดเก็บไฟล์size_tแต่เพียงครั้งเดียวและไม่เคยคัดลอกที่ไหน สิ่งเหล่านี้อาจดูเหมือนประสิทธิภาพเล็กน้อย แต่โปรดทราบว่าเรากำลังพูดถึงเครื่องระดับไฮเอนด์ที่มี RAM 256 KiB

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

แต่เดี๋ยวก่อน! นี่คือปี 1977 และความเข้ากันได้แบบย้อนหลังจะไม่ถูกคิดค้นขึ้นอีก 5 ปี! และนอกจากนี้ไม่มีใครจริงจังใช้สิ่ง "Unix" ที่คลุมเครือนี้ด้วยชื่อที่ไม่เป็นสี K&R ฉบับแรกกำลังจะไปถึงผู้จัดพิมพ์แล้ว แต่ก็ไม่มีปัญหา - มันบอกในหน้าแรกว่า "C ไม่มีการดำเนินการใด ๆ เพื่อจัดการกับวัตถุผสมโดยตรงเช่นสตริงอักขระ ... ไม่มีฮีป ... ". ณ จุดนี้ในประวัติศาสตร์string.hและmallocเป็นส่วนขยายผู้ให้บริการ (!) ดังนั้นแนะนำ Bearded Man # 1 เราสามารถเปลี่ยนแปลงได้ตามที่เราต้องการ ทำไมเราไม่ประกาศผู้จัดสรรที่ยุ่งยากของคุณให้เป็นผู้จัดสรรอย่างเป็นทางการล่ะ

ไม่กี่วันต่อมา Bearded Man # 2 เห็น API ใหม่และบอกว่าเดี๋ยวก่อนรอก่อนดีกว่า แต่ก็ยังใช้จ่ายทั้งคำต่อการจัดสรรเพื่อจัดเก็บขนาด เขามองว่านี่เป็นสิ่งต่อไปของการดูหมิ่น คนอื่นมองเขาเหมือนเขาเป็นบ้าเพราะคุณจะทำอะไรได้อีก? คืนนั้นเขานอนดึกและคิดค้นตัวจัดสรรใหม่ที่ไม่ได้เก็บขนาดเลย แต่จะสรุปได้ทันทีโดยการใช้เวทมนตร์ดำบนค่าตัวชี้และเปลี่ยนมันในขณะที่ยังคง API ใหม่ไว้ API ใหม่หมายความว่าไม่มีใครสังเกตเห็นสวิตช์ แต่พวกเขาสังเกตเห็นว่าเช้าวันรุ่งขึ้นคอมไพเลอร์ใช้ RAM น้อยลง 10%

และตอนนี้ทุกคนมีความสุข: คุณได้รับโค้ดที่ง่ายต่อการเขียนและเร็วขึ้น Bearded Man # 1 จะเขียนง่าย ๆstrdupที่ผู้คนจะใช้งานได้จริงและ Bearded Man # 2 - มั่นใจว่าเขาได้รับเงินมาเล็กน้อย - - กลับไปmessing รอบด้วย quines จัดส่ง!

หรืออย่างน้อยนั่นคือสิ่งที่อาจเกิดขึ้นได้


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

5
คุณชนะ. นี่เป็นคำอธิบายที่น่าเชื่อถือที่สุดสำหรับฉัน (และเป็นงานเขียนที่ดีที่สุด) แม้ว่าทุกสิ่งที่นี่จะได้รับการพิสูจน์ว่าไม่ถูกต้องหรือไม่ถูกต้อง แต่ก็เป็นคำตอบที่ดีที่สุดสำหรับการแสดงภาพผู้ชายที่มีหนวดมีเครา
jaymmer - คืนสถานะ Monica

ว้าวคำตอบในหน้านี้ที่ฟังดูน่าเชื่อถือจริงๆ +1 จากฉัน
user541686

ดียิ่งขึ้น - คำตอบในหน้านี้ที่สนุกจริง! +1 ด้วย.
David C. Rankin

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

31

"เหตุใดfreeใน C จึงไม่ใช้จำนวนไบต์ที่จะปลดปล่อย"

เพราะไม่มีความจำเป็นสำหรับมันและมันก็ไม่สมเหตุสมผลอยู่ดี

เมื่อคุณจัดสรรบางสิ่งคุณต้องการบอกระบบว่าจะจัดสรรกี่ไบต์ (ด้วยเหตุผลที่ชัดเจน)

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

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

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


ถ้าฉันยืมเงินคุณ $ 100 แล้วยืม $ 100 จากคุณอีกครั้งแล้วทำอีกห้าครั้งคุณสนใจไหมที่ฉันยืมเงินจากคุณเจ็ดครั้ง (เว้นแต่คุณจะคิดดอกเบี้ยจริงๆ!) ?? หรือคุณสนใจแค่ว่าฉันยืมเงินจากคุณ 700 เหรียญ? สิ่งเดียวกันที่นี่: ระบบให้ความสำคัญกับหน่วยความจำที่ไม่ได้ถูกจัดสรรเท่านั้นไม่ (และไม่จำเป็นและไม่ควร) สนใจว่าหน่วยความจำที่จัดสรรจะถูกแบ่งออกอย่างไร
user541686

1
@ Mehrdad: ไม่และก็ไม่ได้ C แม้ว่าจะทำ จุดประสงค์ทั้งหมดคือการทำให้สิ่งต่างๆ (เล็กน้อย) ปลอดภัยยิ่งขึ้น ฉันไม่รู้จริงๆว่าคุณกำลังมองหาอะไรที่นี่
Lightness Races ใน Orbit

12
@ user3477950: ไม่จำเป็นต้องส่งผ่านจำนวนไบต์ : ใช่เพราะมันถูกออกแบบมาด้วยวิธีนี้ OP ถามว่าทำไมถึงออกแบบมาแบบนี้?
Deduplicator

5
"เพราะมันไม่จำเป็นต้อง" - มันอาจได้รับการออกแบบมาอย่างดีเพื่อให้จำเป็น
user253751

5
@ Mehrdad ว่าการเปรียบเทียบที่ไม่ชัดเจนและผิดพลาดอย่างสมบูรณ์ หากคุณจัดสรรเวลา 4 ไบต์ต่อร้อยครั้งแน่นอนที่สุดก็ไม่สำคัญว่าคุณจะว่างแบบไหน การปลดปล่อยอันที่ 1 นั้นไม่เหมือนกับการปลดปล่อยอันที่สอง ด้วยเงินในทางกลับกันมันไม่สำคัญว่าคุณจะชำระคืนเงินกู้ครั้งแรกหรือครั้งที่สองครั้งแรกมันเป็นเพียงกองใหญ่
2520938

14

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

ในระยะสั้น นี้เป็นจุดทั้งหมดของการเขียนที่เป็นนามธรรม


9
ไม่แน่ใจว่าการจัดตำแหน่งหรือช่องว่างภายในเกี่ยวข้องกับสิ่งนี้อย่างไร คำตอบไม่ได้ตอบอะไรจริงๆ
user541686

1
@Mehrdad C ไม่ใช่ภาษา x86 มันพยายาม (มากหรือน้อย) ที่จะพกพาได้และทำให้โปรแกรมเมอร์เป็นอิสระจากภาระที่สำคัญนั้น คุณสามารถไปถึงระดับนั้นได้ด้วยวิธีอื่น ๆ (เช่นการประกอบแบบอินไลน์) แต่สิ่งที่เป็นนามธรรมคือกุญแจสำคัญ ฉันเห็นด้วยกับคำตอบนี้
Marco A.

4
@ Mehrdad: ถ้าคุณขอmallocN ไบต์และมันส่งกลับตัวชี้ไปที่จุดเริ่มต้นของทั้งหน้าแทน (เนื่องจากการจัดแนวช่องว่างภายในหรือข้อ จำกัด อื่น ๆจะไม่มีทางที่ผู้ใช้จะติดตามมันได้ - บังคับให้พวกเขาทำ มันจะเป็นการต่อต้าน
Michael Foukarakis

3
@MichaelFoukarakis: mallocสามารถส่งกลับตัวชี้ที่จัดตำแหน่งได้ตลอดเวลาโดยไม่ต้องจัดเก็บขนาดของการจัดสรร freeจากนั้นสามารถปัดเศษขึ้นเพื่อจัดตำแหน่งที่เหมาะสมเพื่อให้แน่ใจว่าทุกอย่างเป็นอิสระอย่างเหมาะสม ไม่เห็นมีปัญหาตรงไหน
user541686

6
@ Mehrdad: ไม่มีประโยชน์สำหรับงานพิเศษทั้งหมดที่คุณเพิ่งพูดถึง นอกจากนี้การส่งผ่านsizeพารามิเตอร์เพื่อfreeเปิดแหล่งที่มาของจุดบกพร่องอื่น
Michael Foukarakis

14

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

ไม่มีตัวจัดสรรพื้นที่ผู้ใช้จนกว่า Unix V6 (โปรแกรมจะใช้sbrk()) ใน Unix V6 iolib รวมตัวจัดสรรด้วยalloc(size)และไฟล์free()เรียกที่ไม่ใช้อาร์กิวเมนต์ขนาด แต่ละบล็อกหน่วยความจำนำหน้าด้วยขนาดและตัวชี้ไปยังบล็อกถัดไป ตัวชี้ถูกใช้เฉพาะในบล็อกว่างเมื่อเดินรายการฟรีและถูกนำมาใช้ซ้ำเป็นหน่วยความจำบล็อกในบล็อกที่ใช้งาน

ใน Unix 32V และใน Unix V7 สิ่งนี้ถูกแทนที่ด้วยใหม่malloc()และfree()การนำไปใช้โดยที่free()ไม่ได้sizeโต้แย้ง การนำไปใช้งานเป็นรายการแบบวงกลมแต่ละกลุ่มนำหน้าด้วยคำที่มีตัวชี้ไปยังกลุ่มถัดไปและบิต "ไม่ว่าง" (จัดสรร) เลยmalloc()/free()ไม่ได้ติดตามขนาดที่ชัดเจน


10

เหตุใดfreeใน C จึงไม่ใช้จำนวนไบต์ที่จะปลดปล่อย

เพราะไม่จำเป็นต้อง ข้อมูลมีอยู่แล้วในการจัดการภายในที่ดำเนินการโดย malloc / ฟรี

ข้อควรพิจารณาสองประการ (ที่อาจมีหรือไม่มีส่วนในการตัดสินใจนี้):

  • เหตุใดคุณจึงคาดหวังว่าฟังก์ชันจะได้รับพารามิเตอร์ที่ไม่ต้องการ

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

  • freeฟังก์ชันที่เปลี่ยนแปลงจะทำอย่างไรในกรณีเหล่านี้

    มันจะไม่ฟรี (ทำให้หน่วยความจำรั่ว?)? ไม่สนใจพารามิเตอร์ที่สอง? หยุดแอปพลิเคชันโดยโทรออกหรือไม่ การใช้สิ่งนี้จะเพิ่มจุดล้มเหลวเพิ่มเติมในแอปพลิเคชันของคุณสำหรับคุณลักษณะที่คุณอาจไม่ต้องการ (และหากคุณต้องการโปรดดูจุดสุดท้ายของฉันด้านล่าง - "การใช้โซลูชันที่ระดับแอปพลิเคชัน")

แต่ฉันอยากรู้ว่าทำไมถึงทำแบบนี้ตั้งแต่แรก

เพราะนี่คือวิธีที่ "เหมาะสม" ที่จะทำ API ที่ควรจะต้องมีการขัดแย้งจะต้องมีการดำเนินการของมัน, และไม่เกินที่

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

วิธีที่เหมาะสมในการนำไปใช้ ได้แก่ :

  • (ในระดับระบบ) ภายในการนำ malloc ไปใช้ - ไม่มีอะไรหยุดยั้งผู้ใช้ห้องสมุดจากการเขียน malloc เพื่อใช้กลยุทธ์ต่างๆภายในโดยพิจารณาจากขนาดที่ได้รับ

  • (ที่ระดับแอปพลิเคชัน) โดยการรวม malloc และฟรีภายใน API ของคุณเองและใช้สิ่งเหล่านี้แทน (ทุกที่ในแอปพลิเคชันของคุณที่คุณอาจต้องการ)


6
@ user3477950: ไม่จำเป็นต้องส่งผ่านจำนวนไบต์ : ใช่เพราะมันถูกออกแบบมาด้วยวิธีนี้ OP ถามว่าทำไมถึงออกแบบมาแบบนี้?
Deduplicator

4
"เพราะไม่จำเป็นต้อง" - อาจมีการออกแบบมาอย่างดีเพื่อให้จำเป็นโดยไม่บันทึกข้อมูลนั้น
user253751

1
สำหรับประเด็นที่ 2 ของคุณคุณมีฉันสงสัยว่าพฤติกรรมที่กำหนด (NULL) ฟรีหรือไม่ Aha, "ไลบรารี C เวอร์ชันที่เป็นไปตามมาตรฐานทั้งหมดถือว่าฟรี (NULL) เป็นแบบไม่ใช้งาน" - ที่มาstackoverflow.com/questions/1938735/…
Mawg กล่าวว่า Monica คืนสถานะ

10

ห้าเหตุผลที่ควรคำนึงถึง:

  1. สะดวกดีครับ ช่วยขจัดภาระค่าใช้จ่ายทั้งหมดจากโปรแกรมเมอร์และหลีกเลี่ยงข้อผิดพลาดที่ยากมากในการติดตาม

  2. จะเปิดโอกาสในการปล่อยส่วนหนึ่งของบล็อก แต่เนื่องจากโดยปกติแล้วผู้จัดการหน่วยความจำต้องการมีข้อมูลการติดตามจึงไม่ชัดเจนว่านี่หมายถึงอะไร?

  3. Lightness Races In Orbit เป็นจุดที่เกี่ยวกับช่องว่างภายในและการจัดตำแหน่ง ลักษณะของการจัดการหน่วยความจำหมายความว่าขนาดจริงที่จัดสรรไว้ค่อนข้างจะแตกต่างจากขนาดที่คุณขอ ซึ่งหมายความว่าfreeจะต้องมีขนาดและสถานที่mallocจะต้องเปลี่ยนเพื่อส่งคืนขนาดจริงที่จัดสรรเช่นกัน

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

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

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

เพิ่มในภายหลัง

อีกคำตอบหนึ่งที่ค่อนข้างน่าขันได้นำstd :: ตัวจัดสรรมาเป็นข้อพิสูจน์ว่าfreeสามารถทำงานในลักษณะนี้ได้ แต่ในความเป็นจริงมันเป็นตัวอย่างที่ดีว่าทำไมfreeไม่ทำงานในลักษณะนี้ มีความแตกต่างที่สำคัญสองประการระหว่าง what malloc/ freedo และ std :: ตัวจัดสรรทำ ประการแรกmallocและfreeกำลังเผชิญหน้ากับผู้ใช้ - ออกแบบมาเพื่อให้โปรแกรมเมอร์ทั่วไปทำงานด้วย - ในขณะที่std::allocatorออกแบบมาเพื่อให้การจัดสรรหน่วยความจำเฉพาะไปยังไลบรารีมาตรฐาน นี่เป็นตัวอย่างที่ดีเมื่อคะแนนแรกของฉันไม่สำคัญหรือไม่สำคัญ เนื่องจากเป็นไลบรารีความยากลำบากในการจัดการความซับซ้อนของขนาดการติดตามจึงถูกซ่อนไว้ไม่ให้ผู้ใช้เห็น

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

- * หากใครยังคงเข้าใจประเด็นนี้ยากให้พิจารณาสิ่งนี้: ตัวจัดสรรหน่วยความจำทั่วไปจะเพิ่มข้อมูลการติดตามจำนวนเล็กน้อยไปยังจุดเริ่มต้นของบล็อกหน่วยความจำจากนั้นจะส่งกลับค่าชดเชยของตัวชี้จากสิ่งนี้ โดยทั่วไปข้อมูลที่เก็บไว้ที่นี่จะมีตัวชี้ไปยังบล็อกถัดไปที่ไม่เสียค่าใช้จ่ายตัวอย่างเช่น สมมติว่าส่วนหัวมีความยาวเพียง 4 ไบต์ (ซึ่งจริงๆแล้วเล็กกว่าไลบรารีจริงส่วนใหญ่) และไม่รวมขนาดลองนึกภาพว่าเรามีบล็อกฟรี 20 ไบต์เมื่อผู้ใช้ขอบล็อก 16 ไบต์ซึ่งไร้เดียงสา ระบบจะส่งคืนบล็อก 16 ไบต์ แต่จากนั้นปล่อยให้ชิ้นส่วน 4 ไบต์ที่ไม่สามารถใช้งานได้โดยเสียเวลาทุกครั้งmallocถูกเรียก หากผู้จัดการเพียงแค่ส่งกลับบล็อก 20 ไบต์แทนก็จะบันทึกส่วนที่ยุ่งเหยิงเหล่านี้จากการสร้างและสามารถจัดสรรหน่วยความจำที่มีอยู่ได้อย่างหมดจดมากขึ้น แต่ถ้าระบบต้องดำเนินการอย่างถูกต้องโดยไม่ต้องติดตามขนาดตัวเองเราก็ต้องให้ผู้ใช้ติดตาม - สำหรับทุก ๆ การจัดสรรครั้งเดียว - จำนวนหน่วยความจำที่จัดสรรจริงหากต้องการส่งคืนฟรี อาร์กิวเมนต์เดียวกันนี้ใช้กับช่องว่างภายในสำหรับประเภท / การจัดสรรที่ไม่ตรงกับขอบเขตที่ต้องการ ดังนั้นอย่างมากการกำหนดfreeขนาดจึงเป็นสิ่งที่ (a) ไร้ประโยชน์โดยสิ้นเชิงเนื่องจากตัวจัดสรรหน่วยความจำไม่สามารถพึ่งพาขนาดที่ส่งผ่านเพื่อให้ตรงกับขนาดที่จัดสรรจริงหรือ (b) ต้องการให้ผู้ใช้ทำงานติดตามของจริงอย่างไร้จุดหมาย ขนาดที่จัดการได้อย่างง่ายดายโดยตัวจัดการหน่วยความจำที่เหมาะสม


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

ฉันยอมรับและไม่ได้รับการยอมรับ - ดูเหมือนจะเป็นคำตอบที่ดี แต่ดูเหมือนว่าคำถามจะมีกิจกรรมมากมายฉันคิดว่าฉันอาจจะคลอดก่อนกำหนดเล็กน้อย สิ่งนี้ทำให้ฉันคิดอะไรบางอย่างได้อย่างแน่นอน
jaymmer - คืนสถานะ Monica

2
@jaymmer: ใช่มันคลอดก่อนกำหนด ฉันขอแนะนำให้รอมากกว่าหนึ่งหรือสองวันก่อนที่จะยอมรับและฉันขอแนะนำให้คุณคิดด้วยตัวเอง เป็นคำถามที่น่าสนใจจริงๆและคำตอบส่วนใหญ่ / ทั้งหมดที่คุณจะได้รับในตอนแรกสำหรับคำถาม "ทำไม" ใน StackOverflow จะเป็นเพียงความพยายามกึ่งอัตโนมัติในการปรับระบบปัจจุบันแทนที่จะตอบคำถามที่แท้จริง
user541686

@ Mehrdad: คุณเข้าใจผิดในสิ่งที่ฉันพูดใน # 4 ฉันไม่ได้บอกว่ามันจะใช้ขนาดพิเศษฉันกำลังบอกว่า (a) มันจะย้ายใครต้องจัดเก็บขนาดดังนั้นมันจะไม่ประหยัดพื้นที่ใด ๆ และ (b) การเปลี่ยนแปลงที่เกิดขึ้นมีแนวโน้มที่จะทำได้จริง ประสิทธิภาพน้อยกว่าไม่มาก สำหรับ # 5 ฉันไม่มั่นใจว่ามันเป็นที่ถกเถียงกันอยู่เลย: เรากำลังพูดถึงการบันทึกคำแนะนำสองสามข้อจากการโทรฟรี เมื่อเทียบกับค่าโทรฟรีที่จะมีขนาดเล็ก
Jack Aidley

1
@ Mehrdad: โอ้และใน # 3 ไม่ต้องใช้ข้อมูลเพิ่มเติม แต่ต้องใช้หน่วยความจำเพิ่มเติม ตัวจัดการหน่วยความจำทั่วไปที่ออกแบบมาเพื่อทำงานกับการจัดตำแหน่ง 16 ไบต์จะส่งกลับตัวชี้ไปที่บล็อก 128 ไบต์เมื่อถามถึงบล็อก 115 ไบต์ หากการfreeโทรจะต้องผ่านขนาดที่ถูกต้องจึงจะต้องทราบสิ่งนี้
Jack Aidley

5

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

แต่เดิมถือว่าสะดวกและไม่สามารถปรับปรุงได้หลังจากนั้น
ไม่มีเหตุผลที่น่าเชื่อสำหรับเรื่องนี้ (แต่ฉันยินดีจะลบสิ่งนี้หากแสดงว่ามันไม่ถูกต้อง)

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


สำหรับหลาย ๆ คน (จำนวนมาก1 !) ที่คิดว่าการผ่านขนาดนั้นไร้สาระมาก:

ฉันขอแนะนำคุณเกี่ยวกับการตัดสินใจออกแบบของ C ++ สำหรับstd::allocator<T>::deallocateวิธีการนี้ได้หรือไม่

วัตถุทั้งหมดในพื้นที่ที่ชี้ไปจะถูกทำลายก่อนการเรียกนี้ จะต้องตรงกับค่าที่ส่งไปเพื่อรับหน่วยความจำนี้n Tp
nallocate

ฉันคิดว่าคุณจะมีเวลา"น่าสนใจ"ในการวิเคราะห์การตัดสินใจออกแบบนี้


สำหรับข้อเสนอoperator delete2013 N3778 ("C ++ Sized Deallocation") มีจุดมุ่งหมายเพื่อแก้ไขปัญหานั้นด้วยเช่นกัน


1เพียงแค่ดูความคิดเห็นในคำถามเดิมเพื่อดูว่ามีกี่คนที่ยืนยันอย่างเร่งรีบเช่น"ขนาดที่ถามไม่มีประโยชน์สำหรับการfreeโทร"เพื่อระบุว่าไม่มีsizeพารามิเตอร์


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

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

std::allocatorจัดสรรเฉพาะองค์ประกอบที่มีขนาดเฉพาะและเป็นที่รู้จัก ไม่ใช่ตัวจัดสรรวัตถุประสงค์ทั่วไปการเปรียบเทียบคือแอปเปิ้ลกับส้ม
Jack Aidley

สำหรับฉันแล้วดูเหมือนว่าการตัดสินใจออกแบบเชิงปรัชญาบางส่วนเป็นการตัดสินใจบางส่วนเพื่อทำให้ไลบรารีมาตรฐานใน C เป็นชุดดั้งเดิมขั้นต่ำที่แทบจะไม่สามารถสร้างอะไรก็ได้ - เดิมมีจุดมุ่งหมายเพื่อเป็นภาษาระดับระบบและแบบพกพาไปยังระบบวิธีการดั้งเดิมนี้ทำให้ ความรู้สึก. ด้วย C ++ มีการตัดสินใจที่แตกต่างออกไปเพื่อทำให้ไลบรารีมาตรฐานกว้างขวางมาก (และขยายใหญ่ขึ้นด้วย C ++ 11) ฮาร์ดแวร์ที่พัฒนาได้เร็วขึ้นความทรงจำที่มากขึ้นสถาปัตยกรรมที่ซับซ้อนมากขึ้นและความจำเป็นในการจัดการกับการพัฒนาแอปพลิเคชันระดับสูงอาจมีส่วนในการเปลี่ยนจุดเน้นนี้
Clifford

1
@Clifford: แน่นอน - นั่นเป็นเหตุผลที่ฉันบอกว่าไม่มีเหตุผลที่น่าเชื่อถือสำหรับมัน เป็นเพียงการตัดสินใจที่เกิดขึ้นและไม่มีเหตุผลที่จะเชื่อว่าดีกว่าทางเลือกอื่นอย่างเคร่งครัด
user541686

2

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


5
ผมคิดว่า "จินตนาการทั้งหมด [ ... ] ข้อผิดพลาด" เป็นที่สงสัยเมื่อคุณคิดว่าโรงงานข้อผิดพลาดอื่น ๆ เช่นgets, printfลูปด้วยตนเอง (ออกโดยหนึ่ง) พฤติกรรมที่ไม่ได้กำหนดรูปแบบสตริงแปลงนัยเทคนิคบิต et สุสาน.
Sebastian Mach

1

ฉันขอแนะนำว่าเป็นเพราะสะดวกมากที่จะไม่ต้องติดตามข้อมูลขนาดด้วยตนเองด้วยวิธีนี้ (ในบางกรณี) และมีแนวโน้มที่จะเกิดข้อผิดพลาดของโปรแกรมเมอร์น้อยกว่า

นอกจากนี้ realloc ต้องการข้อมูลการทำบัญชีนี้ซึ่งฉันคาดว่าจะมีมากกว่าขนาดการจัดสรร กล่าวคืออนุญาตให้กลไกที่ใช้ทำงานได้ถูกกำหนดไว้

คุณสามารถเขียนตัวจัดสรรของคุณเองซึ่งทำงานได้ค่อนข้างตรงตามที่คุณแนะนำและมักจะทำใน c ++ สำหรับตัวจัดสรรพูลในลักษณะที่คล้ายกันสำหรับกรณีเฉพาะ (ซึ่งอาจได้รับประสิทธิภาพสูงมาก) แม้ว่าโดยทั่วไปจะใช้ในแง่ของตัวดำเนินการ ใหม่สำหรับการจัดสรรบล็อกพูล


1

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


ไม่จำเป็นต้องมีช่องขนาดที่ชัดเจน มันสามารถมีตัวชี้ไปยังบล็อกถัดไปและบิตที่จัดสรรได้
ninjalj

0

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

หากคุณทำงานใน Linux และคุณต้องการทราบจำนวนไบต์ / ตำแหน่งที่ malloc จัดสรรไว้คุณสามารถสร้างโปรแกรมง่ายๆที่ใช้ malloc หนึ่งครั้งหรือ n ครั้งและพิมพ์คำแนะนำที่คุณได้รับ นอกจากนี้คุณต้องทำให้โปรแกรมเข้าสู่โหมดสลีปสักครู่ (เพียงพอสำหรับการดำเนินการต่อไปนี้) หลังจากนั้นเรียกใช้โปรแกรมนั้นค้นหา PID ของมันเขียน cd / proc / process_PID แล้วพิมพ์ "cat maps" ผลลัพธ์จะแสดงให้คุณเห็นในบรรทัดเดียวทั้งจุดเริ่มต้นและที่อยู่หน่วยความจำสุดท้ายของพื้นที่หน่วยความจำฮีป (ที่คุณกำลังจัดสรรหน่วยความจำแบบไดนามิก) หากคุณพิมพ์พอยน์เตอร์ไปยังพื้นที่หน่วยความจำเหล่านี้ที่ถูกจัดสรรคุณ สามารถเดาได้ว่าคุณจัดสรรหน่วยความจำไว้เท่าใด

หวังว่าจะช่วยได้!


0

ทำไมต้อง? malloc () และ free () เป็นพื้นฐานการจัดการหน่วยความจำที่เรียบง่ายมากโดยเจตนาและการจัดการหน่วยความจำระดับสูงใน C นั้นขึ้นอยู่กับผู้พัฒนาเป็นส่วนใหญ่ ที

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

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

คุณติดแท็กคำถาม C ++ เช่นเดียวกับ C และถ้า C ++ คือสิ่งที่คุณใช้อยู่คุณแทบไม่ควรใช้ malloc / free ไม่ว่าในกรณีใด ๆ นอกเหนือจากใหม่ / ลบคลาสคอนเทนเนอร์ STL จะจัดการหน่วยความจำโดยอัตโนมัติและในลักษณะที่เป็นไปได้ ให้เหมาะสมเป็นพิเศษกับลักษณะของภาชนะต่างๆ


ยิ่งไปกว่านั้น realloc () ก็ทำเช่นนั้นแล้ว - ถ้าคุณลดการจัดสรรใน realloc () มันจะไม่ย้ายข้อมูลและตัวชี้ที่ส่งกลับจะเหมือนเดิม พฤติกรรมนี้รับประกันหรือไม่? ดูเหมือนว่าจะเป็นเรื่องปกติในตัวจัดสรรแบบฝังหลายตัว แต่ฉันไม่แน่ใจว่าพฤติกรรมนี้ถูกระบุเป็นส่วนหนึ่งของ standard-c หรือไม่
rsaxvc

@rsaxvc: คำถามที่ดี - เอกสารcplusplus.com "หากขนาดใหม่ใหญ่ขึ้นมูลค่าของส่วนที่จัดสรรใหม่จะไม่แน่นอน" หมายความว่าถ้ามีขนาดเล็กมันเป็นเด็ดขาด [opengroup.org () ระบุว่า"ถ้าขนาดใหม่ของวัตถุหน่วยความจำต้องการการเคลื่อนไหวของวัตถุพื้นที่สำหรับการสร้างอินสแตนซ์ก่อนหน้าของวัตถุจะถูกปล่อยให้ว่าง" - หากมีขนาดเล็กกว่าข้อมูลก็ไม่จำเป็นต้องย้าย ความหมายอีกครั้งคือขนาดเล็กจะไม่สามารถจัดสรรใหม่ได้ ฉันไม่แน่ใจว่ามาตรฐาน ISO ระบุว่าอย่างไร
Clifford

1
reallocเป็นอย่างยิ่งที่ได้รับอนุญาตให้ย้ายข้อมูล ตามมาตรฐาน C ก็หมดทางกฎหมายในการดำเนินการreallocเป็นmalloc+ +memcpy freeและมีเหตุผลที่ดีว่าทำไมการนำไปใช้งานอาจต้องการย้ายการจัดสรรที่ลดขนาดลงเช่นเพื่อหลีกเลี่ยงการแยกส่วนหน่วยความจำ
Nathaniel J. Smith
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.