มีทางเลือกอื่นสำหรับสแต็ก + ฮีป + โมเดลหน่วยความจำสแตติก


9

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

มีความพยายามใด ๆ ในการจัดระเบียบเค้าโครงหน่วยความจำข้อมูลด้วยวิธีที่แตกต่างอย่างสิ้นเชิงเช่นไม่มี call stack หรือไม่? หรือจัดระเบียบหน่วยความจำในวิธีอื่นที่ทำสิ่งเดียวกันสำเร็จ?


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

และขึ้นอยู่กับสิ่งที่คุณหมายถึง "เมื่อเร็ว ๆ นี้" ฉันคิดว่าการจัดเก็บในตัวชุดข้อมูลของเธรดนั้นเก่าแก่เท่ากับชุดข้อความ แต่ก่อนหน้านี้สามารถเข้าถึงได้ผ่านการโทรของระบบในขณะที่ภาษาที่ใหม่กว่าให้คุณเข้าถึงได้โดยตรง
DXM

call stack มีความจำเป็นเนื่องจากฟังก์ชั่นขั้นตอนจำเป็นต้องรู้ว่าใครเรียกพวกเขาเพื่อให้พวกเขาสามารถส่งกลับผลลัพธ์และดำเนินการต่อไป กลไกปัจจุบันหากการทำเช่นนั้นค่อนข้างถูกในแง่ของรอบการทำงานของ CPU และด้วย x64 อย่างน้อยฟังก์ชัน args เกือบทั้งหมดจะถูกส่งผ่านการลงทะเบียน
James

2
คุณอาจพบโพสต์ของ Eric Lippert ทำไมต้อง Stack? ที่น่าสนใจ ประเด็นหลักของเขาคือสแต็กให้วิธีที่มีประสิทธิภาพและง่ายต่อการติดตามตำแหน่งหน่วยความจำ เขากล่าวถึงทางเลือกหนึ่งในหลาย ๆ โพสต์เก่ามากต่อเนื่องผ่านสไตล์
Brian

คำตอบ:


8

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

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

ทุกครั้งที่มีการสร้างเธรดมีโครงสร้างข้อมูลบางส่วน (และสแต็ก) ซึ่งได้มาโดยใช้ "การดำเนินการ gimme" ที่ฉันเพิ่งอธิบาย สแต็กใช้กันอย่างแพร่หลายเพราะมันเข้ากันได้ดีกับฟังก์ชั่นคอลเฟรมและธรรมชาติของ LIFO ในทางทฤษฎีแต่ละฟังก์ชั่นการร้องขอและตัวแปรโลคัลสามารถจัดสรรบนฮีปได้ แต่นั่นอาจมีราคาแพงเกินไปเมื่อเทียบกับคำแนะนำในการประกอบเพียงไม่กี่คำที่ใช้ในการอัปเดตสแต็กตัวชี้ (ESP บน x86)

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

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

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

"memory model" ประเภทอื่นคือ Virtual Memory Manager (VMM) ที่นำเสนอโดยเกือบทุกระบบปฏิบัติการหลักผ่านการเรียกของระบบ VMM นั้นคล้ายกับฮีปในแง่ที่คุณสามารถขอจำนวนหน่วยความจำและเก็บไว้ได้นานเท่าที่คุณต้องการ อย่างไรก็ตามข้อ จำกัด คือคุณสามารถจัดสรรหน่วยความจำได้เฉพาะในการคูณขนาดหน้า (เช่น 4KB) ดังนั้นการใช้ VMM โดยตรงจะทำให้เกิดโอเวอร์เฮดจำนวนมากในแอปพลิเคชันทั่วไปที่มักจะจัดสรร 8-24 ไบต์ต่อครั้ง ในความเป็นจริงการใช้ heap เกือบทุกครั้งนั้นถูกสร้างขึ้นบน VMM โดยเฉพาะเพื่อวัตถุประสงค์ในการอนุญาตการจัดสรรบล็อกขนาดเล็กทั่วไปที่ไม่เฉพาะเจาะจง ฮีปไปที่ VMM เมื่อใดก็ตามที่ต้องการหน่วยความจำเพิ่มเติมจากนั้นดึงก้อนเล็ก ๆ จำนวนมากของหน่วยความจำนั้นไปยังแอปพลิเคชัน

หากคุณมีแอปที่มีความจำเป็นในการจัดสรรบล็อกขนาดใหญ่คุณอาจพิจารณาไปที่ VMM โดยตรงแม้ว่าบาง heaps จะมีคำสั่ง if ใน malloc () และถ้าขนาดบล็อกใหญ่กว่าขีด จำกัด บางส่วนพวกเขาเพียงไปที่ VMM สำหรับคุณ.

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

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

นอกเหนือจากสิ่งที่ฉันพูดถึงฉันแน่ใจว่ามีรูปแบบพิเศษอื่น ๆ อีกมากมาย แต่ในท้ายที่สุดเนื่องจากทุกอย่างขึ้นอยู่กับพื้นที่ที่อยู่ตามลำดับ (นั่นคือจนกว่า genuis บางคนจะมาพร้อมกับพื้นที่แปลก ๆ แบบ a-a $$ ) ทุกอย่างกลับไปที่ตัวจัดสรร "gimme" ทั่วไปซึ่งเป็น VMM หรือฮีป


1

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

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

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

ดังนั้นสิ่งที่คุณคิดค้นเพื่อแทนที่หนึ่งในสามเหล่านี้จะจบลงด้วยการมองหามากเหมือนหนึ่งในสามเหล่านี้ในที่สุด ...

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

... ดังนั้นจนกว่าจะมีใครคิดแบบก้าวกระโดดครั้งใหญ่ฉันคิดว่าเราไม่น่าจะเห็นการเปลี่ยนแปลงครั้งใหญ่ในพื้นที่นี้เป็นเวลานาน ...


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

@Anaught: ด้านพลิกไปโต้แย้งของคุณคือคนอื่นใช้เวลาเงินและพลังงานคิดนอกกรอบและทุก ๆ 1,000 (อาจจะมากกว่า) ของพวกเขาหนึ่งในที่สุดอาจก้าวหน้าทางเทคโนโลยีในขณะที่คนที่เหลืออยู่ที่ไหน . ในขณะที่กลุ่มแรกที่ใคร ๆ คิดว่าสามารถนำไปปฏิบัติได้มากกว่านั้นให้นำโมเดลที่มีอยู่เหล่านี้ไปใช้ตามเดิมและสร้างสรรค์สิ่งใหม่ ๆ บนสุดของพวกเขา :)
DXM

@aaraught ฉันคิดว่าฉันครอบคลุมด้วย "ดังนั้นจนกว่าจะมีคนมาพร้อมกับการก้าวกระโดดแนวคิดขนาดใหญ่บางชนิด";) หากคุณมีรูปแบบทางเลือกที่ดีกว่าอย่าลังเลที่จะแนะนำ ... ถ้าไม่รู้สึกเสแสร้งที่จะบ่นเกี่ยวกับ "บางคน" เมื่อคุณเป็นหนึ่งในพวกเขา :)
ทิม B

1
@DXM: งั้นเหรอ? ฉันพูดว่าเราทุกคนควรสละเวลาของเราในการค้นคว้ารูปแบบหน่วยความจำใหม่หรือไม่? ฉันแค่ชี้ให้เห็นข้อบกพร่อง (นัยสำคัญ) ในการกล่าวอ้างว่าบุคคลสามารถประดิษฐ์สิ่งต่าง ๆ ที่ได้ประดิษฐ์ขึ้นแล้วเท่านั้น
Aaronaught

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