ورود

View Full Version : سوالاتی حول ذخیره داده ها در حافظه



deCODER-
سه شنبه 19 اسفند 1393, 17:20 عصر
خسته نباشید دوستان ...
یک سری سوال برام پیش اومده که اگر پاسخ بدید ممنون میشم.
1-میخواستم بدونم وقتی میگن تابع در حافظه ذخیره شده منظورشون چیه؟آیا متغیر های یک تابع یا متد در خافظه ذخیره میشن یا اینکه خود تابع دخیره میشه واگه تابع دخیره میشه ، چگونه؟
2-دوم اینکه کد هایی که مینویسیم تا دستوراتی به سی پی یو منتقل کنه، این ها چطور در حافظه ذخیره میشن؟
چون من الان به خاطر اینکه فقط با ذخیره سازی داده ها در متغیرها اشنا هستم، این جور مسائل منو سردرگم کرده.

deCODER-
چهارشنبه 20 اسفند 1393, 16:19 عصر
کسی پاسخگو نیس؟ من عجله دارم شرمنده :ناراحت::ناراحت::ناراحت:

محمد فدوی
چهارشنبه 20 اسفند 1393, 17:15 عصر
سلام. اول این توضیح رو بدم که پاسخ سؤالتون باتوجه به نوع معماری پردازنده، سیستم‌عامل (هسته‌ی سیستم‌عامل)، ماشین مجازی جاوای در حال اجرا (OracleJDK یا OpenJDK ...) و عواملی از این نوع می‌تونه متغیر باشه.
۱. توی زبان‌هایی مثل ++C نه، صرفا یه بار تابع کامپایل می‌شه و یه اشاره‌گر بش تخصیص پیدا می‌کنه که اون اشاره‌گر مسیر اجرا رو به همین سگمنت کامپایل شده (یعنی همین تابع کامپایل شده) هدایت می‌کنه. این در مورد توابع عضو معمولی ++C بودن. در مورد توابع مجازی (Virtual) یه کم ماجرا متفاوته و باعث می‌شه کلاس کمی سنگین‌تر بشه ولی درنهایت همین ساختار «هدایت به کد کامپایل شده» که در بالا گفتم وجود داره. در مورد جاوا هم حدس من اینه که نحوه‌ی پیاده‌سازی کم‌وبیش همین‌طوری باشه.

۲. در مورد جاوا، شما یه برنامه‌رو می‌نویسی و کامپایل می‌کنی. نتیجه می‌شه یه فایل بایت‌کد (bytecode) با پسوند class ؛ بایت‌کد چیزیه مشابه اسمبلی که از یه سری دستورالعمل ساده و ثابت تشکیل شده. فقط با این مزیت که بایت‌کد رو ماشین مجازی جاوا می‌تونه روی هر سیستم‌عاملی و بصورت مستقل از سکو اجرا کنه. در مقابل اسمبلی کدیه که مستقیما توسط ماشین قابل فهمه و بیش از حد وابسته به سکوئه (و طبعا سریع‌تر). این بایت کد در زمان اجرا توسط ماشین مجازی جاوا خونده می‌شه و کد‌ماشین معادلش تولید می‌شه (یعنی همون کدی که مستقیما برای ماشین قابل فهمه).

موفق باشی.

deCODER-
شنبه 23 اسفند 1393, 09:03 صبح
دوست عزیز صمن تشکر فراوان بابت پاسختون ، اما متاسفانه من پاسخ خودمو اونجوری که باید دریافت نکردم.حدس میزنم سوال منو خوب متوجه نشده باشید.سوال من این بود که "اینکه میگن تابع در حافظه ذخیره میشه آیا منظورشون اینه که متغیر های تابع در حافظه ذخیره میشن؟" و اینکه " کل کدی که ما مینویسیم،مث متغیر ها در حافظه قرار میگیرن یا نه؟"

تشکر :قلب:

محمد فدوی
شنبه 23 اسفند 1393, 16:42 عصر
دوست عزیز صمن تشکر فراوان بابت پاسختون ، اما متاسفانه من پاسخ خودمو اونجوری که باید دریافت نکردم.حدس میزنم سوال منو خوب متوجه نشده باشید.سوال من این بود که "اینکه میگن تابع در حافظه ذخیره میشه آیا منظورشون اینه که متغیر های تابع در حافظه ذخیره میشن؟" و اینکه " کل کدی که ما مینویسیم،مث متغیر ها در حافظه قرار میگیرن یا نه؟"

تشکر :قلب:

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

-سیّد-
دوشنبه 24 فروردین 1394, 07:54 صبح
سؤالی که در مورد ذخیره‌سازی توابع در حافظه پرسیدید در زبان‌های compiler-based و interpreter-based متفاوت هست. البته توی هر دوشون همونطور که دوستمون گفت توی حافظه فضا اشغال می‌کنن، این نحوه‌اش هست که فرق می‌کنه.

مثلاً توی ++C، کد شما به کد ماشین ترجمه می‌شه و این کد توی حافظه قرار می‌گیره. بعد CPU به این بخش از حافظه هدایت می‌شه که اجراش کنه. یعنی دقیقاً همونطور که متغیرها توی حافظه قرار می‌گیرن، کد هم توی حافظه قرار می‌گیره. ولی با ۲ تا تفاوت:
یکی این که در جای متفاوت قرار می‌گیرن: متغیرها توی Data segment یا Stack یا Heap هستند، ولی کد توی Code segment هست.
دوم این که زمان قرارگیریشون توی حافظه فرق می‌کنه. متغیرها هنگام allocate شدن توی حافظه قرار می‌گیرن (ممکنه همون اول اجرای کد باشه، ممکنه موقع new شدن باشه، ممکنه موقع فراخوانی یک تابع باشه که متغیرهای محلی خودش رو توی پشته allocate می‌کنه). اما کد شما همون اول اجرا، کلش توی حافظه قرار می‌گیره و شروع به اجرا می‌شه.

مثلاً اگه یه تابع داشته باشید که توش ۱۰ تا دستور دارید و ۲ تا متغیر محلی، اگه فرق کنیم هر دستور شما به طور متوسط ۱۰ بایت فضا اشغال می‌کنه، کد شما می‌شه ۱۰۰ بایت (دستورات مختلف فضای متفاوت اشغال می‌کنن، مثلاً یه مقداردهی (x = 10) تبدیل می‌شه به یه دستور زبان ماشین که می‌گه مقدار ۱۰ رو بریز توی خونه‌ی فلان حافظه، ولی یه دستور شرطی (if x==10) تبدیل می‌شه به ۲ یا ۳ تا دستور. دستورات پیچیده‌تر هم به تعداد بیشتری دستور زبان ماشین ممکنه تبدیل بشن). بنابراین موقع اجرای کد، ۱۰۰ بایت فضا بهش اختصاص داده می‌شه (حتی اگه این تابع هیچوقت توی این اجرا فراخوانی نشه، مثلاً فرض کنید کد مربوط به فشار دادن یه دکمه توی یه برنامه که ممکنه از هر ده نفر یه نفر فشارش بدن!). اما اون ۲ تا متغیر، فقط در صورت فراخوانی تابع شما حافظه بهشون اختصاص داده می‌شه. بنابراین در صورت فراخوانی تابع، مثلاً اگه یه int و یه long داشته باشید، ۱۲ بایت حافظه‌ی اضافه هم اشغال می‌شه (البته بعضی اطلاعات دیگه هم درباره‌ی خود تابع وجود دارن که اونا هم اشغال می‌شن). این رو هم دقت کنید که میزان حافظه‌ی مختص کد، تقریباً هیچ ارتباطی به تعداد و نوع متغیرهای تعریف شده نداره.

توجه کنید که داده‌ای که به عنوان کد توی حافظه ذخیره می‌شه، با داده‌ای که به عنوان متغیر توی حافظه ذخیره می‌شه، هیچ فرقی با همدیگه ندارن. این نوع نگاه ما به اوناس که فرق می‌کنه. یعنی ممکنه شما مقدار ۹۷ رو توی یه بایت از حافظه ذخیره کنید. آیا می‌تونید با اطمینان بگید که اینجا حتماً یه متغیر بوده که مقدارش ۹۷ بوده؟ یا شاید یه متغیر از نوع char بوده که مقدارش 'a' بوده! یا شاید هم یه کدی بوده که موقع تبدیل به زبان ماشین، یکی از بایت‌هاش شده ۹۷. بنابراین همه‌ی حافظه یه شکل هست و از بایت‌ها تشکیل شده. مهم اینه که اون حافظه برای چه کاری استفاده می‌شه.

اما توی جاوا:
اینجا قضیه یه کم فرق می‌کنه. شما کد جاوا رو چطوری اجرا می‌کنید؟ احتمالاً از توی IDE با فشار دادن یه دکمه! اما اون پشت چه اتفاقی می‌افته؟ یه چنین دستوری اجرا می‌شه:

java -cp target ir.test.Test
یعنی برنامه‌ای که داره اجرا می‌شه، برنامه‌ی java هست نه برنامه‌ی شما! اگه توی فهرست process های در حال اجرا هم نگاه کنید، اسمی از برنامه‌ی شما نیست و java هست که اجرا می‌شه.
برای همین، به محض اجرای یه برنامه‌ی جاوا، کل کد JVM توی حافظه بارگزاری می‌شه و هنوز هیچ خبری از برنامه‌ی شما توی حافظه نیست.
بعد از این که کد JVM شروع به اجرا می‌کنه و سلام و احوالپرسیش با سیستم عامل تموم می‌شه (اینها برای ما هیچی نیست و در حد چند میلی‌ثانیه طول می‌کشه! در نتیجه نمی‌فهمیم که اون پشت چه اتفاقاتی افتاده. بدبخت کامپیوتر اون پشت هزاران دستور اجرا می‌کنه تا یه برنامه شروع به کار کنه)، حالا میاد command line خودش رو بررسی می‌کنه که ببینه چه پارامترهایی بهش دادید. می‌بینه بهش گفتید:

-cp target ir.test.Test
شروع می‌کنه به آنالیز کردن این دستورات. می‌بینه زدید cp- و می‌فهمه منظور اینه که می‌خواین آدرس classpath رو بهش بدین (یعنی جایی که byte-code شما قرار داده). داخل خودش تنظیم می‌کنه که آدرس فایل‌های class توی دایرکتوری target هست. بعد پارامتر بعدی رو می‌بینه که نوشتید ir.test.Test و می‌فهمه منظور اینه که کد main شما در این کلاس قرار داره. هنوز هیچ بخشی از سیستم هییییییچ کاری با کد جاوای شما نداشته! تازه اینجا JVM می‌ره به سراغ فایل class متناظر (که می‌شه target/ir/test/Test.class ) و اون رو شروع به بارگذاری توی حافظه می‌کنه.

حالا اگه گفتید توی کدوم حافظه بارگذاری می‌شه؟

نخیر اشتباه گفتید! توی حافظه‌ی کد بارگذاری نمی‌شه! کد جاوای شما که به byte-code تبدیل شده، در واقع یه جورایی یه متغیر هست برای JVM. برای همین توی حافظه‌ی متغیرها ذخیره می‌شه (احتمالاً توی heap). بعدش تازه JVM شروع می‌کنه به اجرای byte-code بارگذاری شده.

یه کم پیچیده شد؟! اگه جاییش رو متوجه نشدید بپرسید تا توضیح بدم.