มีข้อเสียเปรียบในการจัดสรรสแต็กจำนวนมากสำหรับอาร์เรย์เดียวในระบบฝังตัวหรือไม่?


12

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

ฉันกำลังใช้งานโค้ดที่มีอยู่ซึ่งฉันพยายามปรับปรุง (ออกแบบปัญหาที่เป็นไปได้การแสดง ฯลฯ ) รหัสนี้วิ่งบน MCU 8bit เก่ามีเพียง4KB ของแรม ในรหัสนี้ฉันต้องเผชิญกับการใช้งานของอาร์เรย์เกือบ 1KB (ใช่1KB ในระบบRAM 4KB ) แต่ละไบต์ของอาร์เรย์นี้ถูกใช้นั่นไม่ใช่คำถาม ปัญหาคือว่าอาร์เรย์นี้เป็นอาร์เรย์แบบคงที่ในไฟล์ที่มีการประกาศดังนั้นวงจรชีวิตของมันเป็นเช่นเดียวกับโปรแกรมหนึ่ง (เช่นถือได้ว่าไม่มีที่สิ้นสุด)

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

ทีนี้คำถาม: นี่เป็นความคิดที่ดีไหม? จากมุมมองการออกแบบหากไม่ต้องการวงจรชีวิตที่ไม่มีที่สิ้นสุด / ทั่วโลกมันเป็นของสแต็ค แต่เดี๋ยวก่อนนั่นคือ 1KB จาก 4KB ไม่มีข้อเสียในการจัดสรร RAM 25% ของแบบนี้ใช่ไหม? (นั่นอาจเป็น 50% หรือมากกว่าของสแต็ก)

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

สิ่งเดียวที่ฉันใส่ใจคือฉันต้องทำให้แน่ใจว่าจริง ๆ แล้วฉันมีสแต็ก 1KB ฟรีเมื่อเข้าสู่ฟังก์ชันนี้ บางทีนั่นอาจเป็นสิ่งที่ฉันต้องระวัง


4
คุณเขียน "และดังนั้นจึงบันทึก RAM ขนาด 1KB นี้" บันทึกไว้เพื่ออะไร 1KB นั้นจะต้องพร้อมใช้งานเมื่อคุณต้องการมันสำหรับอาร์เรย์ดังนั้นทำไมไม่ทำการจัดสรรแบบคงที่? คุณมีการใช้งานอื่นสำหรับหน่วยความจำเมื่อไม่จำเป็นสำหรับอาร์เรย์หรือไม่?
kkrambo

@kkrambo ในบางครั้งเราคิดว่าระบบเต็มเมื่อเราไม่สามารถเพิ่มอะไรเพิ่มเติมใน RAM ไม่ว่าจะเป็นสิ่งที่คงที่หรือบนสแต็ก ถ้าเราวางอาร์เรย์นี้ลงบนสแต็กเมื่อเราใช้เท่านั้นมันจะปล่อยให้ฟังก์ชันอื่นทำงานได้ตราบใดที่มันไม่ได้ใช้พร้อมกัน แต่คำถามนั้นถูกต้องทั้งหมดในขณะนี้หากเราไม่เปลี่ยนแปลงอะไรใน SW เราไม่ต้องการ RAM เพิ่มอีก)
Tim

1
คุณสามารถอธิบายได้ไหมว่าอาเรย์นี้มีเนื้อหาที่ยังคงเหมือนเดิมหรือไม่หรือเปลี่ยนแปลงเมื่อมีการเรียกใช้ฟังก์ชันที่ใช้หรือไม่
Blrfl

@Blrfl มันเปลี่ยนทุกครั้งที่มีการเรียกใช้ฟังก์ชัน
ทิม

คำตอบ:


8

สิ่งเดียวที่ฉันใส่ใจคือฉันต้องทำให้แน่ใจว่าจริง ๆ แล้วฉันมีสแต็ก 1KB ฟรีเมื่อเข้าสู่ฟังก์ชันนี้

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

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

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

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


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

คุณไม่สามารถรับ (บางทีโดยการรวบรวม GCC จากซอร์สโค้ด) คอมไพเลอร์ GCC สำหรับแพลตฟอร์มของคุณหรือไม่
Basile Starynkevitch

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

3
การขอเจ้านายของคุณให้รับ GCC รุ่นใหม่ (โดยมอบเครื่องมือไบนารีที่ทันสมัยให้คุณหรือให้เวลาคุณในการรวบรวม GCC ใหม่) เป็นสิ่งที่คุ้มค่ากับ IMHO เพราะ GCC อาจค่อนข้างใหม่กว่าจะเหมาะกว่า (คุณรู้gcc -flto -Osหรือไม่? ) และคุณอาจได้รับความทรงจำ ....
Basile Starynkevitch

2
มันกำลังดำเนินการ แต่จะไม่มาก่อนในขณะที่ ฉันใช้ -Os กับระบบอื่น ๆ ด้วย toolchains รุ่นล่าสุดแล้ว แต่ฉันไม่ทราบถึงพารามิเตอร์ -flto นี้ขอบคุณที่ชี้ให้เห็น (โปรดทราบว่าฉันได้ทำการทดสอบเล็กน้อยกับ GCC -Os และ -O1-3 พารามิเตอร์เมื่อไม่กี่สัปดาห์ที่ผ่านมาใน GCC 5.4.1 และ RAM ก็เหมือนกันตลอดเวลา FLASH และ MCU ที่ใช้เวลาทำงานต่างกัน นั่นไม่ได้อยู่บน MCU เดียวกันกับที่ฉันพูดถึงใน Q / A)
ทิม

6

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

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

มิฉะนั้นคุณสามารถทำสิ่งที่คุณต้องการด้วย RAM ของคุณ


4

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

ข้อเสนอแนะในการแบ่งปันบล็อกกับข้อมูลอื่น ๆ ที่มีการรวมกันเป็น IMO ที่ถูกต้องแม้ว่ามันจะเป็นแหล่งที่มาของปัญหาที่หายากถ้าคุณค้นหาตัวแปรที่ไม่ถูกต้อง

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


1

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


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

1

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

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

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