تبلیغات

Stack و Heap یا پشته چیست؟!

سی شارپ - Stack (پشته) و Heap چیست؟

حافظه کامپیوتر از نظر مفهومی به تعدادی قطعه‌ی جداگانه تقسیم شده است. دوتا از این قطعات، Stack و Heap نامیده می‌شوند. این دو قطعه برای اهداف متفاوتی در نظر گرفته شده‌اند.

Stack و Heap چیست؟

وقتی که متدی را فراخوانی می‌کنیم، پارامترها و متغیرهای محلی آن، احتیاج به حافظه دارند؛ که حافظه‌ی مورد نیاز برای پارامترها و متغیرهای محلی، همیشه از Stack تامین می‌شود. و سپس وقتی که کار متد به پایان می‌رسد، (یا به خاطر این که متد به فراخواننده خود برمی‌گردد و یا به خاطر اینکه Exception ایجاد کرده است)، این حافظه اختصاص داده شده به صورت خودکار به Stack برگردانده می‌شود!

وقتی که نمونه‌ای از یک کلاس ایجاد می‌کنیم (که معمولا با استفاده از کلیدواژه‌ی new و یک constructor در اکثر زبان‌های برنامه‌نویسی انجام می‌شود)، و ازآنجایی که برای ایجاد این آبجکت بدون هیچ شکی حافظه مورد نیاز است، این حافظه همیشه از Heap تامین می‌شود! وقتی که کار متد به پایان می رسد، (یا به خاطر این که متد به فراخواننده خود برمی گردد و یا به خاطر اینکه Exception ایجاد کرده است)، این حافظه به صورت خودکار به Heap برگردانده نمی‌شود. (در مثال‌ها این مورد را بهتر درک خواهید کرد)


هنگامی‌که شما در اپلیکیشن‌های .NET متغیری تعریف می‌کنید، قسمتی از حافظه‌ی RAM برای این منظور اختصاص داده می‌شود. این قسمت از حافظه، شامل سه چیز است:

  • نوع متغیر.
  • نام متغیر.
  • مقدار متغیر.

int

یک مثال ساده را در زبان سی‌شارپ بررسی می‌کنیم:

  • فرض کنید مقداری که در param به متد داده می‌شود، 42 است. یک قطعه‌ی کوچک از حافظه (که برای یک int کافی است) از stack اختصاص داده می‌شود. مقدار داخل این قطعه‌ی کوچک، با یک الگوی بیتی که نشان دهنده‌ی مقدار عددی 42 است، مقداردهی می‌شود. پس اینگونه param مقداردهی می‌شود.
  • زمان تعریف Circle، مقدار آن برخلاف param با null پر می‌شود؛ سپس وقتی در ادامه نمونه‌ای از کلاس ایجاد می‌شود، یک قطعه‌ی دیگر از حافظه (به اندازه‌ی مورد نیاز برای یک Circle) از heap اختصاص داده می‌شود؛ و به مقدار circle در stack، رفرنس‌دهی شده و به جای null می‌نوشیند! بنابراین مواردی مقدار متغیرهایی که به صورت شیء هستند، در Heap قرار می‌گیرند.

یک مثال دیگر با توضیح بیشتر:

  • وقتی دستور اول اجرا می‌شود: کامپایلر مقدار کمی از حافظه را در stack برای این منظور اختصاص می‌دهد. stack مسئول پیگیری حافظه‌ی مورد نیاز (در حال اجرا) در اپلیکیشن شما است. و همانطور که پیش از این با نحوه‌ی ذخیره‌سازی اطلاعات در stack آشنا شدید، stack عملیات Last In First Out را اجرا می‌کند. (یعنی آخرین مقدار وارد شده، اول از همه به بیرون می‌رود!)
  • وقتی دستور دوم اجرا می‌شود: متغیر y در بالای stack ذخیره خواهد شد؛ یعنی اینکه x در زیر آن قرار خواهد گرفت.
  • وقتی دستور سوم اجرا می‌شود: ما یک شیء به‌وجود آورده‌ایم و در این‌جا اندکی داستان متفاوت می‌شود. ابتدا متغیر ob در stack ذخیره می‌شود و شیء ای که ساخته شده در heap قرار می‌گیرد. نکته دقیقاً همین جاست که reference ها در stack ذخیره می‌شوند و عبارت MyClass ob حافظه را برای یک شیء از این کلاس اشغال نمی‌کند. این عبارت تنها متغیر ob را در stack قرار می‌دهد (و به آن مقدار null می‌دهد) و هنگامی‌که کلمه‌ی کلیدی new اجرا می‌شود، شیء این کلاس در heap ذخیره خواهد شد. در نهایت هنگامی که برنامه به انتهای متد می‌رسد، متغیرهایی که در stack بودند همگی پاک می‌شوند. توجه کنید که پس از به پایان رسیدن متد چیزی از heap پاک نمی‌شود؛ بلکه اشیای درون heap بعداً توسط garbage collector (زباله روب) پاک خواهند شد.

چرا دوتا؟!

stackHeap

شاید سوالی برایتان پیش بیاید که چرا stack و heap را نمیشود همه در یک جا ذخیره شوند؟!

اگر با دقت به تصویر فوق نگاه کنید، می‌بینید که نوع‌داده‌‎(data type)های اصلی (value types یا primitive type = داده‌های اولیه)، پیچیده و سنگین نیستند. آنها مقادیر تکی مثل int i = 5 را نگه می‌دارند، در حالی که object data types یا reference types پیچیده‌تر و سنگین‌تر هستند؛ و آنها به اشیای دیگری رجوع می‌کنند. به عبارت دیگر، آنها به چندین مقدار رجوع می‌کنند (زیرا اشیاء می‌توانند شامل مقادیر زیادی از فیلد و متد و… باشند) که هرکدام از آن‌ها باید در حافظه ذخیره شده باشد. و  همچنین اشیاء، به dynamic memory (حافظه پویا) و داده‌های اصلی به static memory (حافظه استاتیک یا پایدار) نیاز دارند. اگر اطلاعات شما نیازمند dynamic memory باشد، در heap ذخیره می‌شود و اگر نیازمند static memory باشد، در stack ذخیره خواهد شد.

داده‌های اصلی و داده‌های رفرنسی

اکنون که با مفاهیم stack و heap آشنا شدید؛ و بهتر می‌توانید مفهوم value types و reference types را درک کنید. Value type ها تمام و کمال در stack ذخیره می‌شوند؛ یعنی هم مقدار و هم متغیر، همگی یک‌جا هستند؛ ولی در reference type، متغیر در stack است درحالی‌که object در heap قرار می‌گیرد و متغیر و شیء به هم متصل می‌شوند (متغیر به شیء اشاره می‌کند).

در زیر، data type ای از جنس int داریم با اسم i که مقدارش به متغیری از نوع int با اسم j اختصاص داده می‌شود. این دو متغیر در stack ذخیره می‌شوند. و هنگامی‌که مقدار i را به j اختصاص می‌دهیم، یک کپی (کاملاً جدا و مجزا) از مقدار i به j داده می‌شود و به عبارت دیگر هنگامی که یکی از آن‌ها را تغییر دهید، دیگری تغییر نمی‌یابد:

valueTypes

ولی هنگامی‌که یک شیء می‌سازید و reference آن را با یک reference دیگر مساوی قرار می‌دهید، آن‌گاه هر دوی این reference ها به یک شیء رجوع می‌کنند و تغییر هر کدام از آن‌ها باعث تغییر شیء می‌شود؛ زیرا هردو reference به یک شیء اشاره می‌کنند.

همان‌طور که می‌بینید، ابتدا یک شیء ساخته و سپس reference دیگری تعریف کرده‌ایم و نهایتاً آن‌ها را مساوی هم قرار داده‌ایم. توجه کنید که برای ob2، شیء جدید تعریف نکرده‌ایم؛ بلکه ob2 به همان شیءای رجوع می‌کند که ob1 به آن رجوع می‌کند. بنابراین تغییر هرکدام بر روی شیء تاثیر می‌گذارد. همان‌طور که می‌بینید، ob1.Name و ob2.Family در ابتدا برابر با Hadi Akbarzadeh است؛ ولی سپس با تغییر ob2.Name و ob2.Family به Ian Somerhalder مقادیر فیلدهای ob1 نیز تغییر خواهند کرد. referenceType

 

تبلیغات
2 نظر
کانال تلگرام فول کده
تبلیغات

درباره نویسنده

هادی اکبرزاده

[ مدیر فول کده ]

علاقه‌مند به اشتراک گذاری اطلاعات در هر زمینه‌ای / برنامه‌نویس / مدیر فول کده

پاسخ دهید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

نظرات ثبت شده 2 دیدگاه

    1. حمیده گفت:

      سلام در ترجمه یک متن کلمه heap رو چجوری باید ترجمه کنیم؟dereference رو چطور؟ ممنون

      1. سلام، stack و heap هردو به معنی پشته هستند اما تفاوت هاشون که در پست گفته شد اونارو از هم متمایز میکنه. بهتره تو ترجمه به این صورت بگیم:
        stack رو بگیم پشته ی ثابت (که برای تخصیص حافظه استاتیک است) معنی دیگه میشه پشته ی منظم
        heap رو بگیم پشته ی پویا (که برای تخصیص حافظه پویا است) معنی دیگه میشه پشته ی نامنظم
        و خلاصه با یکی از ویژگی های دیگشون میتونید موقع ترجمه بهش صفت اختصاص بدین

        در مورد dereference بهتره خودش رو استفاده کنید یا بهتره معنی ارجاع مجدد رو براش استفاده کنید.