เหตุใดเราจึงต้องมีฮีปหากทุกอย่างสามารถทำได้อย่างมีประสิทธิภาพมากขึ้นในสแต็ก


24

นี่เป็นคำถามเกี่ยวกับคำถามที่ฉันถามเมื่อวานนี้ว่าทำไมทั้ง Stack และ Heap จึงมีความจำเป็นในแอปพลิเคชันที่เราใช้ในวันนี้ (และทำไมเราไม่สามารถไปกับ Heap ได้แทนที่จะเป็นทั้งสองอย่าง มาตรฐานเอกพจน์ที่จะไปด้วย)

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


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

2
หลักฐานของคุณมีข้อบกพร่อง - ไม่ใช่ทุกสิ่งที่สามารถทำได้อย่างมีประสิทธิภาพมากขึ้นในสแต็ค นี่ไม่ขัดแย้งกับคำตอบที่คุณได้รับ - สิ่งที่สามารถทำได้บนสแต็กนั้นสามารถทำได้เร็วกว่ามาก
Ingo

... สมมติว่าฮาร์ดแวร์ของคุณมีสแต็กหรือการกำหนดสแต็กที่สัมพันธ์กัน
Ritch Melton

3
ฉันเชื่อมั่น ฉันว่ามันทำ
JeffO

คำตอบ:


25

ปัญหาเกี่ยวกับสแต็คคือคุณไม่สามารถ "ฟรี" หน่วยความจำจนกว่าจะอยู่ด้านบนสุดของสแต็ก ตัวอย่างเช่นสมมติว่าคุณจัดสรร 3 ขนาดที่แตกต่างกัน:

a = allocate(2000000); // 2000000 bytes
b = allocate(1);
c = allocate(5000000);

สแต็คจะมีaที่ด้านล่างbตรงกลางและcด้านบน สิ่งนี้จะเป็นปัญหาหากเราต้องการให้ฟรีb:

free(b); // b is not on top! We have to wait until c is freed!

วิธีแก้ปัญหาคือการย้ายข้อมูลทั้งหมดหลังจากที่และการเปลี่ยนแปลงถ้าเพื่อที่จะมาหลังจากb aใช้งานได้ แต่จะต้องมี500,000ชุดในกรณีนี้สิ่งที่จะช้ากว่ากองมาก

นี่คือเหตุผลที่เรามีกอง ในขณะที่การจัดสรรอาจช้ากว่าสแต็ค ( O(log n)vs O(1)) ฮีปอนุญาตให้เพิ่มหน่วยความจำในตำแหน่งที่กำหนดเองได้อย่างรวดเร็ว - O(log n)เปรียบเทียบกับสแต็กของO(n)


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

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

2
@deadalnix ที่จริงแล้วเป็นตัวอย่างของการใช้ stack ขนาดใหญ่แทนที่จะเป็น heap ที่ปกติจะใช้สำหรับหน่วยความจำจำนวนมาก Facebook เป็นกรณีพิเศษ ข้อมูลถูกเพิ่มเร็วกว่าการลบการจัดสรรคืนไม่ได้สร้างความแตกต่างอย่างมีนัยสำคัญต่ออัตราการเติบโต - คุณสามารถจงใจรวมการรั่วไหลของหน่วยความจำในการออกแบบเพื่อให้ได้การจัดสรร O (1)
Tom Clarkson

7
@PaulTomblin เหตุผลหลักที่ FB ไม่ได้ลบเนื้อหาคือเพื่อให้พวกเขาสามารถขุดมันเพื่อผลกำไรของพวกเขา ...
quant_dev

5
Facebook doesn't remove content from its disk when you ask it to remove it, it just removes the pointer to it- ซึ่งเป็นสิ่งสำคัญที่จะเกิดขึ้นเมื่อคุณลบไฟล์ปกติในระบบปฏิบัติการใด ๆ
Robert Harvey

5

สแต็คเป็นแบบต่อเธรดฮีปมีทั้งกระบวนการ

หากมี 100 เธรดไอเท็มการประมวลผลงานทั้งหมดที่ฉันใส่ลงในคิวฉันจะจัดสรรไอเท็มงานได้ตรงไหนที่ 100 เธรดใด ๆ สามารถเห็นได้?

มีหน่วยความจำประเภทอื่นด้วย

เช่นไฟล์ที่แม็พหน่วยความจำ, หน่วยความจำที่แชร์, I / O ที่แมป (โหมดเคอร์เนล) อาร์กิวเมนต์ประสิทธิภาพเป็นชนิดที่สงสัยในสถานการณ์เหล่านี้


4

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


3
LIFO ไม่ใช่ FIFO
Pubby

บางครั้งเรียกว่า FILO;)
oenone

3

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

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


0

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


0

ท่ามกลางเหตุผลอื่น ๆ อีกมากมายสำหรับการจัดสรรที่เก็บฮีป

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

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

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