שְׁאֵלָה:
כיצד משתמשים בזיכרון הערימה לפונקציות ולמשתנים מקומיים?
Nafis
2014-07-04 23:15:21 UTC
view on stackexchange narkive permalink

רציתי לשמור כמה ערכים ל- EEPROM ורציתי גם לפנות SRAM על ידי הימנעות מהצהרות משתנות, אבל זיכרון EEPROM הוא חכם בתים.

אם אני רוצה לאחסן ערך int, יש לי להשתמש בכמה ביטויים שוב ושוב. חשבתי שאעשה כמה פונקציות עבור אלה. אבל אני חושש שאם אני יוצר פונקציה, זה עדיין יתפוס את זיכרון ה- SRAM, עדיף שאצהיר על משתנה int במקום להשתמש ב- EEPROM.

כיצד מאוחסנים הפונקציות והמשתנים המקומיים ב- SRAM? האם הוא שומר רק את כתובת מצביע הפוקה מזיכרון הבזק או שכל המשתנים והפקודות מאוחסנים בערימה?

זכור כי EEPROM ניתן לכתב רק למספר מוגבל של פעמים, הקריאה בו אינה מוגבלת. על פי גיליון הנתונים של ה- AVR ל- EEPROM יש רק 100000 מחזורים, שנשמעים הרבה, אבל כשאתה מנסה להשתמש בו כ- SRAM, זה יימשך רק תקופה קצרה למדי.
אוומייגוד! לאחר מכן, האם ה- EEPROM יהיה חסר תועלת? אני הולך לבדוק את גליון הנתונים!
לזיכרון הפלאש יש גם חיי חיים. חכם יותר לא לצרוב את התוכנית הרבה.
בשימוש רגיל המספרים שניתנו לפלאש ו- EEPROM אינם מהווים בעיה כלל. המשוואה משתנה כשמתחילים להשתמש בה כמו שמשתמשים ב- SRAM.
חָמֵשׁ תשובות:
Duncan C
2014-07-04 23:52:09 UTC
view on stackexchange narkive permalink

משתנים מקומיים ופרמטרים של פונקציות מאוחסנים בערימה. עם זאת, זו לא סיבה שלא להשתמש בהם. מחשבים נועדו לעבוד כך.

זיכרון הערימה נמצא בשימוש רק כאשר פונקציה פעילה. ברגע שהפונקציה חוזרת, הזיכרון משתחרר. זיכרון הערימה הוא דבר טוב.

אתה לא רוצה להשתמש בפונקציות רקורסיביות עם הרבה רמות של רקורסיה, או להקצות הרבה מבנים גדולים בערימה. אולם שימוש רגיל הוא בסדר.

מחסנית 6502 היא רק 256 בתים, אך Apple II עובד בסדר גמור.

אז אתה מתכוון שהפונקציה תישמר עם כל המשתנים, הפרמטרים והביטויים המקומיים שלה בערימה באופן זמני, רק כשהיא נקראת? אחרת זה יישאר בתוכנית / בזיכרון הבזק? האם לאחר ההוצאה להורג, הוא יימחק מערימה? דיברתי על Arduino למעשה, מכיוון שזה Arduino Forum, לא הזכרתי את זה.
לא, רק הפרמטרים והמשתנים המקומיים נמצאים על הערימה. קוד הפונקציה לא נשמר בערימה. אל תחשוב יותר מדי על זה.
user2973
2014-07-06 12:23:26 UTC
view on stackexchange narkive permalink

ה- AVR (משפחת המיקרו-בקרים המשמשת באופן מסורתי בלוחות ארדואינו) היא אדריכלות של הרווארד, כלומר קוד הפעלה ומשתנים נמצאים בשני זיכרונות נפרדים - במקרה זה פלאש ו- SRAM. קוד ההפעלה לעולם לא משאיר זיכרון פלאש.

כשאתה קורא לפונקציה כתובת השולח בדרך כלל נדחקת למחסנית - היוצא מן הכלל הוא כאשר שיחת הפונקציה מתרחשת בסוף פונקציית השיחה. במקרה זה תשתמש במקום זאת בכתובת ההחזרה של הפונקציה שקראה לפונקציה הקוראת - היא כבר נמצאת בערימה.
אם נתונים אחרים מוצבים על הערימה תלויה בלחץ הרישום בפונקציית הקריאה ובפונקציה נקרא פונקציה. רושמים הם אזור העבודה של המעבד, ל- AVR יש 32 רושמים של 1 בתים. ניתן לגשת לרשמים ישירות על ידי הוראות מעבד, ואילו תחילה יש לאחסן נתונים ב- SRAM ברשומות. רק אם ארגומנטים או משתנה מקומי גדולים מדי או רבים מכדי להתאים לרשמים, הם יועלו על הערימה. עם זאת, מבנים מאוחסנים תמיד על הערימה.

תוכלו לקרוא את הפרטים על אופן השימוש בערימה על ידי מהדר GCC בפלטפורמת AVR כאן: https://gcc.gnu.org / wiki / avr-gcc # Frame_Layout
קרא את הסעיפים "פריסת מסגרת" ו"וועידת שיחות ".

JRobert
2014-07-04 23:46:37 UTC
view on stackexchange narkive permalink

רק נתוני הפונקציה מאוחסנים בערימה; הקוד שלה נשאר בהבזק. אתה לא באמת יכול להפחית את השימוש ב- SRAM באמצעות EEPROM במקום זאת, כי כפי שראית, EEPROM אינו ניתן לכתובת באותה צורה. הקוד לקריאה ואחסון של EEPROM צריך גם להשתמש ב- SRAM כלשהו - כנראה SRAM בדיוק כמו שניסית לשמור! EEPROM הוא גם איטי לכתיבה, ויש לו אורך חיים מוגבל (במספר כתובות לכל בייט), שניהם הופכים את זה לבלתי מעשי לשימוש לאחסון סוג הנתונים הזמניים שאנו בדרך כלל שמים על הערימה. זה מתאים יותר לשמירת נתונים שהשתנו לעתים רחוקות, כמו תצורת ההתקן הייחודית למכשירים המיוצרים בהמונים, או לכידת שגיאות נדירות לניתוח מאוחר יותר.

ערוך: אין ערימה עבור פונקציה זו עד ש הפונקציה נקראה, אז כן, כאשר כל אחד מהנתונים של הפונקציה מוצב שם. מה שקורה לאחר שהפונקציה חוזרת הוא שמסגרת המחסנית שלה (האזור השמור שלה ב- SRAM) כבר לא שמורה. בסופו של דבר הוא ישתמש מחדש בשיחת פונקציה אחרת. הנה תרשים של מחסנית C בזיכרון. כאשר מסגרת מחסנית כבר אינה שימושית, היא פשוט משוחררת וזיכרונה הופך לשימוש זמין לשימוש מחדש.

אני חושב ככה, כאשר הפונקציה נקראת, רק אז הנתונים בתוכה נשמרים בערימה. לאחר ביצוע הפונקציה הנתונים נמחקים ממחסנית / SRAM. האם אני צודק?
Paul Dent
2015-08-06 00:54:01 UTC
view on stackexchange narkive permalink

מיד עם קריאת פונקציה שנכנסת לפונקציה, הקוד הראשון שמבוצע הוא הפחתת מחסנית הערימה בכמות השווה לשטח הנדרש למשתנים זמניים הפנימיים לפונקציה. הדבר המבריק בכך הוא כי כל הפונקציות הופכות להיות חוזרות ונשנות ורקורסיביות מכיוון שהמשתנים שלהן בנויים על ערימת התוכנית הקוראת. כלומר, אם הפסקה מפסיקה את הביצוע של תוכנית אחת ומעבירה את הביצוע לאחרת, היא גם יכולה לקרוא לאותו דבר. מתפקדים מבלי שהם יפריעו זה לזה.

Nick Gammon
2015-08-06 02:24:01 UTC
view on stackexchange narkive permalink

ניסיתי די קשה להכין דוגמת קוד קוד כדי להדגים מה אומרות התשובות המצוינות כאן, ללא הצלחה עד כה. הסיבה היא שהמהדר מייעל את הדברים בצורה אגרסיבית. עד כה הבדיקות שלי כלל לא השתמשו בערימה, אפילו לא עם משתנים מקומיים בפונקציה. הסיבות הן:


  • המהדר עשוי ל בשורה שיחת הפונקציה, כך שכתובת ההחזרה עשויה בכלל לא להידחף אל הערימה . דוגמה:

    void foo (byte a) {digitalWrite (13, a); } לולאה בטלה () {foo (5); }

    המהדר הופך את זה ל:

    loop loop () {digitalWrite (13, 5); }

    אין שיחת פונקציה, לא נעשה שימוש במחסנית.


  • המהדר רשאי להעביר ארגומנטים ב רושם ובכך יחסוך לו צורך לדחוף אותם למחסנית. דוגמה:

    digitalWrite (13, 1);

    הידור ל:

    158: 8d e0 ldi r24, 0x0D; 1315a: 61 e0 ldi r22, 0x01; 115c: 0e 94 05 01 התקשר 0x20a; 0x20a <digitalWrite>

    הטיעונים מוכנסים לרשומות ולכן לא נעשה שימוש בערימה (מלבד כתובת החזרה להתקשרות ל- DigitalWrite). >

    • משתנים מקומיים עשויים להכניס לרשמים, ושוב חוסכים צורך להשתמש ב- RAM. זה לא רק חוסך זיכרון RAM אלא גם מהיר יותר.

    • המהדר מייעל משתנים שאינך משתמש בהם. דוגמה:

      void foo (byte a) {סרגל ארוך לא חתום [100]; סרגל [1] = א; digitalWrite (9, פס [1]); } לולאה בטלה () {foo (3); } // סוף לולאה

      עכשיו זה חייב להקצות 400 בתים ל"סרגל ", לא? לא:

      00000100 <_Z3fooh>: 100: 68 2f mov r22, r24 102: 89 e0 ldi r24, 0x09; 9 104: 0e 94 cd 00 התקשר 0x19a; 0x19a <digitalWrite> 108: 08 95 ret 0000010a <loop>: 10a: 83 e0 ldi r24, 0x03; 3 10c: 0e 94 80 00 התקשר 0x100; 0x100 <_Z3fooh> 110: 08 95 ret

      המהדר ייעל את ה מערך כולו! זה יכול לומר שאנחנו באמת עושים digitalWrite (9, 3) וזה מה שהוא מייצר.


    מוסר של הסיפור: אל תנסה לחשוב מהמהדר.

רוב הפונקציות הלא טריוויאליות משתמשות בערימה כדי לשמור כמה רושמים, כך שניתן להשתמש בהם בכדי להחזיק משתנים מקומיים. ואז יש לנו מצב מצחיק זה שבו מסגרת המחסנית של הפונקציה מכילה משתנים מקומיים השייכים למתקשר _ זה.


שאלה ותשובה זו תורגמה אוטומטית מהשפה האנגלית.התוכן המקורי זמין ב- stackexchange, ואנו מודים לו על רישיון cc by-sa 3.0 עליו הוא מופץ.
Loading...