در این آموزش قصد داریم تا به تفصیل مفهوم Java Virtual Machine یا به اختصار JVM به معنی «ماشین مجازی جاوا» را مورد بررسی قرار دهیم که در راستای تحقق شعار طراحان این زبان ابداع شده است به طوری که چنین قابلیتی جز با بهکارگیری مفهومی تحت عنوان جِیویاِم امکانپذیر نمیباشد. در واقع، از بدو ایجاد زبان برنامهنویسی جاوا شعار طراحان این زبان مفهومی است که بر اساس آن گفته میشود «!Write One, Run Anywhere» بدین معنی که «یک بار برنامۀ جاوای خود را بنویسید سپس روی هر پلتفرمی که خواستید آن را اجرا کنید!» که چنین قابلیتی صرفاً با بهکارگیری جِیویاِم فراهم شده است. به طور کلی، سازوکار ماشین مجازی جاوا را میتوان در قالب تصویر زیر نشان داد:
همانطور که در تصویر بالا مشخص است، برنامۀ جاوایی که مینویسیم یا همان سورسکد برنامه ابتدا توسط این زبان اصطلاحاً Compile میشود که در اینجا منظور از کامپایل شدن یک برنامه تبدیل کدهای جاوای آن به Bytecode است. پس از کامپایل سورسکد نوشتهشده به زبان جاوا، حال وظیفۀ ماشین مجازی است که برنامهٔ اصطلاحاً Compiled (کامپایلشده) را به شکلی قابلفهم برای پلتفرم مد نظر تبدیل نماید؛ به عبارت دیگر، ماشینهای مجازی تمام تلاش خود را به کار میگیرند تا از روی سورسکدی یکسان نتایج نسبتاً یکسانی را از اجرای آنها روی پلتفرمهای مختلف به دست آورند.
همانطور که در تصویر فوق ملاحظه میکنید، ماشین مجازی جاوا را میتوان به عنوان یک لایۀ مجازی مابین برنامۀ نوشتهشده به زبان جاوا و سیستمعامل مد نظر تلقی کرد مضاف بر اینکه میتوان گفت ماشین مجازی جاوا هیچ گونه عملیاتی روی سورسکد اصلی انجام نمیدهد بدین معنی که برنامۀ مذکور در ابتدا کامپایل شده و در طی این پروسه به بایتکد تبدیل میشود تا برای سیستمعامل مد نظر قابلفهم باشد سپس این بایتکدها به ماشین مجازی داده میشوند تا برای سیستمعاملهای مختلف بهینه گردند (در آموزش بعدی با مفهوم بایتکد و نحوۀ کامپایل یک برنامۀ جاوا به منظور تبدیل به بایتکد آشنا خواهیم شد.)
نکته |
ماشین مجازی جاوا علاوه بر قابلیتهای بسیاری که در اختیار برنامهنویسان قرار میدهد، محدودیتهایی را هم ایجاد میکند که البته این محدودیتها به نوعی راهگشا هستند چرا که منجر به ارتقاء امنیت نرمافزارهای نوشتهشده با جاوا میشوند؛ به عبارت دیگر، با بهکارگیری جِیویاِم دولوپرها به هیچ وجه نمیتوانند بخشی از حافظۀ اختصاصیافته به دیگر قسمتهای برنامه را به زور تصاحب کنند تا بدین طریق بتوانند مثلاً آبجکتی جدید ساخته و فضای حافظه را به آن اختصاص دهند. |
یکی از مزایای کامپایل سورسکد و تبدیل آن به بایتکد این است که بدین طریق میتوان از دیگر زبانهای برنامهنویسی نیز در توسعۀ اپلیکیشنهای نوشتهشده به زبان جاوا استفاده کرد؛ به عبارت دیگر، چنانچه یک زبان برنامهنویسی قابلیتی داشته باشد که بتوان در ابتدا سورسکد مد نظر را کامپایل کرده و آن را به بایتکدی قابلفهم برای جاوا تبدیل کرد، در چنین شرایطی ماشین مجازی جاوا امکان اجرای آن بخش از کد که به زبان دیگری نوشته شده است را در کنار کدهای جاوا دارا است.
آشنایی با مفهوم Garbage Collection
منظور از چنین اصطلاحی در زبان برنامهنویسی جاوا این است که برنامهنویس نیازی به درگیر کردن خود با مسائل مربوط به Memory یا حافظه ندارد چرا که این مسئولیت بر عهدۀ خود ماشین مجازی جاوا گذاشته شده است. در واقع، حافظه در برنامههای جاوا به دو قسمت تقسیم میشود که عبارتند از حافظۀ Heap و حافظۀ Stack که در صورت ایجاد آبجکتی از روی یکی از کلاسهای برنامه، آبجکت ساختهشده در حافظۀ هیپ ذخیره میشود (در آموزشهای آینده با مفهوم آبجکت، کلاس و نحوۀ ساخت آبجکت از روی آن آشنا خواهیم شد.) حال برای روشن شدن نحوۀ عملکرد Garbage Collector در این زبان، مثالی را مد نظر قرار میدهیم بدین صورت که اگر بخواهیم آبجکتی از روی کلاس String
بسازیم خواهیم داشت:
String str = new String();
در کد فوق، آبجکتی از روی کلاس String
تحت عنوان str
ساختهایم و در ادامه آبجکت مذکور در جایی از برنامه مورد استفاده قرار میگیرد و چنانچه این آبجکت پس از مدتی در روند اجرای برنامه به کار گرفته نشود، به نوعی آبجکتی مُرده به حساب میآید.
در واقع، زبانهایی مانند سیپلاسپلاس قابلیت حذف آبجکتهای مُرده را نداشته و این امر به صورت دستی و توسط برنامهنویسان انجام میشود که چنین کاری در برنامههای بزرگ و پیچیده به علت تعاملات متعددی که آبجکتها با یکدیگر دارند به فرآیندی بسیار سخت، پیچیده و پُرخطا مبدل میگردد در حالی که زبان جاوا چنین قابلیتی را دارا بوده و با بهکارگیری گاربج کالکتور آبجکتهای مُرده را از حافظۀ هیپ حذف میکند. در حقیقت، گاربج کالکتور بخشی از ماشین مجازی جاوا است و الگوریتمهای پیچیدهای دارد که بدین ترتیب به صورت خودکار و دورهای به حافظۀ هیپ مراجعه کرده و آبجکتهای مُرده را از آن پاک میکند تا فضای حافظه به منظور نگهداری سایر آبجکتها آزاد گردد.
نکته |
لازم به یادآوری است که دولوپرهای جاوا نیز میتوانند به صورت دستی اقدام به فراخوانی گاربج کالکتور کنند اما چنین کاری هرگز توصیه نمیشود. |
نکتۀ قابلتوجه در رابطه با مثال فوق این است که متغیر str
در این مثال خود یک شیئ نبوده بلکه ارجاعی به آبجکت ساختهشده از روی کلاس مذکور در حافظۀ هیپ است و از همین روی میتوان گفت که متغیر str
در حافظۀ اِستک ذخیره شده است (در زبان برنامهنویسی جاوا مفهومی تحت عنوان اشارهگر وجود ندارد اما در این قسمت میتوان گفت که str
یک نوع اشارهگر است چرا که به آبجکت ساختهشده از روی کلاس String
در حافظۀ هیپ اشاره میکند.)