วัตถุประสงค์ของการจัดตำแหน่งหน่วยความจำ


197

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


17
หลังจากทำGoogling เพิ่มเติมฉันพบลิงค์ที่ยอดเยี่ยมนี้ซึ่งอธิบายปัญหาได้ดีจริงๆ
หีบ

ลองอ่านบทความเล็ก ๆ นี้สำหรับผู้ที่เริ่มเรียนรู้สิ่งนี้: blog.virtualmethodstudio.com/2017/03/memory-alignment-run-fools
darkgaze

3
@ark link broken
John Jiang

2
@JohnJiang ฉันคิดว่าฉันพบลิงก์ใหม่ที่นี่: developer.ibm.com/technologies/systems/articles/pa-dalign
ejohnso49

คำตอบ:


63

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

มีข้อมูลเพิ่มเติมในลิงค์นี้ที่ OP ค้นพบ


311

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

ความเร็ว

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

ซีพียูจะอ่านที่ขนาดของคำ (4 ไบต์บนตัวประมวลผลแบบ 32 บิต) เสมอดังนั้นเมื่อคุณทำการเข้าถึงที่อยู่ที่ไม่ได้ลงนาม - บนตัวประมวลผลที่รองรับ - ตัวประมวลผลจะอ่านหลายคำ CPU จะอ่านหน่วยความจำแต่ละคำตามที่อยู่ที่คุณร้องขอ สิ่งนี้ทำให้การขยายจำนวนมากถึง 2X ของจำนวนธุรกรรมหน่วยความจำที่จำเป็นในการเข้าถึงข้อมูลที่ร้องขอ

ด้วยเหตุนี้มันจึงช้ามากในการอ่านสองไบต์มากกว่าสี่ ตัวอย่างเช่นสมมติว่าคุณมีโครงสร้างในหน่วยความจำที่มีลักษณะดังนี้:

struct mystruct {
    char c;  // one byte
    int i;   // four bytes
    short s; // two bytes
}

บนโปรเซสเซอร์ 32 บิตดูเหมือนว่าจะถูกจัดเรียงตามที่แสดงที่นี่:

เค้าโครงเค้าโครง

โปรเซสเซอร์สามารถอ่านสมาชิกแต่ละคนเหล่านี้ในการทำธุรกรรมเดียว

สมมติว่าคุณมีโครงสร้างรุ่นที่รวบรวมมาอาจจะมาจากเครือข่ายที่บรรจุเพื่อประสิทธิภาพในการส่งข้อมูล มันอาจมีลักษณะเช่นนี้:

โครงสร้างแบบแพ็ค

การอ่านไบต์แรกจะเหมือนกัน

เมื่อคุณขอให้ตัวประมวลผลให้ 16 บิตจาก 0x0005 มันจะต้องอ่านคำจาก 0x0004 และเลื่อนซ้าย 1 ไบต์เพื่อวางไว้ในการลงทะเบียน 16 บิต งานพิเศษบางอย่าง แต่ส่วนใหญ่สามารถจัดการในรอบเดียว

เมื่อคุณขอ 32 บิตจาก 0x0001 คุณจะได้แอมพลิฟายเออร์ 2X ตัวประมวลผลจะอ่านจาก 0x0000 ไปยังการลงทะเบียนผลลัพธ์และเลื่อนไปทางซ้าย 1 ไบต์จากนั้นอ่านอีกครั้งจาก 0x0004 ไปเป็นการลงทะเบียนชั่วคราวเลื่อนไปทางขวา 3 ไบต์จากนั้นORด้วยการลงทะเบียนผลลัพธ์

พิสัย

สำหรับพื้นที่ที่อยู่ที่กำหนดหากสถาปัตยกรรมสามารถสันนิษฐานได้ว่า 2 LSBs นั้นเป็น 0 เสมอ (เช่นเครื่อง 32- บิต) จากนั้นจะสามารถเข้าถึงหน่วยความจำได้มากขึ้น 4 เท่า (หน่วยความจำที่บันทึกไว้ 2 บิตสามารถแทน 4 สถานะที่แตกต่างกัน) หรือจำนวนเดียวกัน ของหน่วยความจำที่มี 2 บิตสำหรับบางสิ่งบางอย่างเช่นธง การถอด 2 LSB ออกจากที่อยู่จะช่วยให้คุณจัดตำแหน่ง 4 ไบต์ เรียกอีกอย่างว่าก้าวย่างของ 4 ไบต์ ทุกครั้งที่มีการเพิ่มที่อยู่จะเป็นการเพิ่มบิต 2 อย่างมีประสิทธิภาพไม่ใช่บิต 0 เช่น 2 บิตสุดท้ายจะยังคงเป็น00เช่นเดิม

สิ่งนี้สามารถส่งผลกระทบต่อการออกแบบทางกายภาพของระบบ หากที่อยู่บัสต้องการบิตที่น้อยกว่า 2 บิตอาจมีพินน้อยกว่าบน CPU และมีร่องรอยบนแผงวงจรน้อยกว่า 2

อะตอมมิกซิตี้

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

ข้อสรุป

ระบบหน่วยความจำของโปรเซสเซอร์นั้นค่อนข้างซับซ้อนและเกี่ยวข้องมากกว่าที่อธิบายไว้ที่นี่ การสนทนาเกี่ยวกับวิธีที่โปรเซสเซอร์ x86 ระบุตำแหน่งหน่วยความจำจริงสามารถช่วยได้ (โปรเซสเซอร์จำนวนมากทำงานคล้ายกัน)

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

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

โบนัส: แคช

การจัดตำแหน่งแบบใหม่สำหรับประสิทธิภาพที่ฉันพูดถึงก่อนหน้านี้คือการจัดตำแหน่งบนบรรทัดแคชซึ่ง (ตัวอย่างเช่นในบาง CPU) 64B

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีการปฏิบัติงานมากสามารถได้รับจากการใช้ประโยชน์จากแคช, ดูที่แกลลอรี่ของตัวประมวลผลผลกระทบแคช ; จากคำถามนี้เกี่ยวกับขนาดแคชบรรทัด

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


struct xyz ต่อไปนี้มีขนาดแตกต่างกันเนื่องจากกฎของสมาชิกแต่ละคนจะต้องเริ่มต้นด้วยที่อยู่ซึ่งเป็นทวีคูณของขนาดและ strcut จะต้องจบลงด้วยที่อยู่ซึ่งเป็นทวีคูณของขนาดที่ใหญ่ที่สุดที่สมาชิกของ struct struct x {short s; // 2 bytes และ 2 padding tytes int i; // 4 ไบต์ถ่าน c; // 1 ไบต์และ 3 padding ไบต์ยาวยาว l; }; struct y {int i; // 4 ไบต์ถ่าน c; // 1 ไบต์และ 1 padding byte short s // 2 ไบต์}; struct z {int i; // 4 ไบต์สั้น s; // 2 ไบต์ถ่าน c; // 1 bytes และ 1 padding byte};
กาวิน

1
หากฉันเข้าใจอย่างถูกต้องเหตุผลที่คอมพิวเตอร์ไม่สามารถอ่านคำที่ไม่ได้จัดแนวในขั้นตอนเดียวก็เพราะว่าผู้ใช้ใช้ 30 บิตและไม่ใช่ 32 บิต ??
GetFree

1
@ chux ใช่มันเป็นความจริงแน่นอนไม่เคยถือ 8088 เป็นการศึกษาที่น่าสนใจเกี่ยวกับการแลกเปลี่ยนระหว่างความเร็วและค่าใช้จ่ายโดยทั่วไปแล้วมันคือ 16-bit 8086 (ซึ่งมีบัสภายนอก 16 บิตเต็มรูปแบบ) แต่มีเพียงครึ่งเดียวของบัสเพื่อประหยัดต้นทุนการผลิต ด้วยเหตุนี้ 8088 จึงจำเป็นต้องใช้สองรอบนาฬิกาในการเข้าถึงหน่วยความจำมากกว่า 8086 เนื่องจากต้องทำการอ่านสองครั้งเพื่อให้ได้คำ 16 บิตเต็ม ส่วนที่น่าสนใจ 8086 สามารถทำคำที่สอดคล้องกับการอ่านแบบ 16 บิตในรอบเดียวการอ่านที่ไม่ได้จัดแนวใช้ 2 ความจริงที่ว่า 8088 มีบัสครึ่งคำที่ปิดบังการชะลอตัวนี้
joshperry

2
@joshperry: การแก้ไขเล็กน้อย: 8086 สามารถทำคำชิด 16 บิตอ่านในสี่รอบในขณะที่ unaligned อ่านใช้เวลาแปด เนื่องจากอินเทอร์เฟซหน่วยความจำช้าเวลาดำเนินการบนเครื่องที่ใช้ 8088 มักจะถูกครอบงำด้วยคำสั่งดึงข้อมูล คำสั่งเช่น "MOV AXX, BX" นั้นเรียกว่าหนึ่งรอบเร็วกว่า "XCHG AX, BX" แต่ถ้าไม่มีคำนำหน้าหรือตามด้วยคำสั่งที่การประมวลผลใช้เวลามากกว่าสี่รอบต่อไบต์รหัสจะใช้เวลานานสี่รอบ ปฏิบัติ ใน 8086 การดึงรหัสบางครั้งสามารถติดตามการทำงานได้ แต่ใน 8088 ยกเว้นว่าใครใช้ ...
supercat

1
จริงมาก @martin ฉันนำไบต์ที่ขยายเหล่านั้นออกเพื่อโฟกัสการสนทนาภายในโครงสร้าง แต่บางทีอาจจะเป็นการดีกว่าถ้าจะรวมไว้
joshperry

22

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

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

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


5

โดยพื้นฐานแล้วสาเหตุคือเม็มโมรี่บัสมีความยาวบางขนาดที่เล็กกว่าขนาดหน่วยความจำมาก

ดังนั้นซีพียูจึงอ่านแคช L1 บนชิปซึ่งมักจะเป็น 32KB ในปัจจุบัน แต่หน่วยความจำบัสที่เชื่อมต่อแคช L1 กับ CPU จะมีความกว้างน้อยกว่าขนาดแคชของขนาดสายแคช นี้จะเป็นคำสั่งของ 128 บิต

ดังนั้น:

262,144 bits - size of memory
    128 bits - size of bus

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

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

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

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


5

@ Joshersry ได้ให้คำตอบที่ดีสำหรับคำถามนี้ นอกเหนือจากคำตอบของเขาแล้วฉันยังมีตัวเลขบางตัวที่แสดงเอฟเฟกต์กราฟิกที่อธิบายไว้โดยเฉพาะอย่างยิ่งแอมพลิฟายเออร์ 2X นี่คือลิงก์ไปยังสเปรดชีตของ Google ที่แสดงว่าลักษณะของการจัดเรียงคำที่ต่างกันมีลักษณะอย่างไร นอกจากนี้ยังมีลิงก์ไปยังส่วนสำคัญ Githubพร้อมรหัสสำหรับการทดสอบ รหัสทดสอบถูกดัดแปลงจากบทความที่เขียนโดย Jonathan Rentzsch ซึ่ง @joshperry อ้างอิง การทดสอบดำเนินการบน Macbook Pro พร้อมโปรเซสเซอร์ Quad-Core 2.8 GHz Intel Core i7 64 บิตและ RAM ขนาด 16GB

ป้อนคำอธิบายรูปภาพที่นี่


4
ทำอะไรxและyพิกัดหมายความว่าอย่างไร
shuva

1
i7 รุ่นหลักคืออะไร (ขอบคุณสำหรับการโพสต์ลิงก์ไปยังโค้ด!)
Nick Desaulniers

2

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


2

หากคุณมีบัสข้อมูล 32 บิตสายที่อยู่ของบัสแอดเดรสที่เชื่อมต่อกับหน่วยความจำจะเริ่มจาก A 2ดังนั้นที่อยู่ที่จัดชิด 32 บิตเท่านั้นจึงจะสามารถเข้าถึงได้ในรอบบัสเดียว

ดังนั้นหากคำครอบคลุมขอบเขตการจัดตำแหน่งที่อยู่ - เช่น A 0สำหรับข้อมูล 16/32 บิตหรือ A 1สำหรับข้อมูล 32 บิตไม่ใช่ศูนย์จำเป็นต้องใช้สองรอบรถบัสเพื่อรับข้อมูล

ชุดสถาปัตยกรรม / คำสั่งบางชุดไม่รองรับการเข้าถึงที่ไม่ได้กำหนดและจะสร้างข้อยกเว้นสำหรับความพยายามดังกล่าวดังนั้นคอมไพเลอร์ที่สร้างรหัสการเข้าถึงที่ไม่ได้จัดแนวนั้นไม่เพียงแค่ต้องการเพิ่มรอบบัส แต่ยังมีคำแนะนำเพิ่มเติม


0

บน PowerPC คุณสามารถโหลดจำนวนเต็มจากที่อยู่แปลก ๆ โดยไม่มีปัญหา

Sparc และ I86 และ (ฉันคิดว่า) Itatnium ยกข้อยกเว้นฮาร์ดแวร์เมื่อคุณลองใช้

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


ใน Sparc นี่เป็น "Bus error" ดังนั้นในบท "Bus error, ขึ้นรถไฟ" ในปีเตอร์แวนเดอร์ลินเด็นเรื่อง "Expert C Programming: Deep C Secrets"
jjg
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.